Is it possible to order a SQLite select result in way that highest value is in the center and lower value are distributed around center till start and end of result set?
data set:
5
3
2
1
1
1
1
desired result:
1
1
3
5
2
1
1
Use ROW_NUMBER() window function to assign a row number to each value and with MAX() window function get the difference of each value from the max value of the table so they can be distributed around the max value:
SELECT *
FROM tablename
ORDER BY CASE WHEN ROW_NUMBER() OVER (ORDER BY col) % 2 = 1 THEN -1 ELSE 1 END *
(MAX(col) OVER () - col)
Change col to the column's name.
See the demo.
I want to display the hourly based report for the last 24 hour. I have tried but the problem is that it will display count only where particular hour contains data.
But I want to display count for an hour and if count not found then display 0 over there.
select
datepart(hour, upload_date) as [hour], count(*)
from
tbl_stories
where
upload_date > getdate() - 1
group by
datepart(hour, upload_date)
Output:
hour count
-------------
11 2
16 1
17 1
but I want to get a record in the following way.
hour count
-------------
1 0
2 0
3 5
.
.
.
.
24 1
You can use a value() clause to generate all the hours and then use left join:
select v.hh, count(s.upload_date)
from (values (0), (1), . . . (23)
) v(hh) left join
tbl_stories s
on datepart(hour, s.upload_date) = v.hh and
s.upload_date > getdate() - 1
group by v.hh
order by v.hh;
Note that hours go from 0 to 23.
If you don't want to list out the hours, a convenient generation method is a recursive CTE:
with hours as (
select 1 as hh
union all
select hh + 1
from hours
where hh < 23
)
select h.hh, count(s.upload_date)
from hours h
tbl_stories s
on datepart(hour, s.upload_date) = h.hh and
s.upload_date > getdate() - 1
group by h.hh
order by h.hh;
I have an SQLite3 database from which I want to remove rows that have two fields of the same value.
It seems that I am able to select such values with this query:
SELECT * FROM mydb GROUP BY user_id, num HAVING COUNT(*) > 1
However I am not able to delete them.
DELETE FROM mydb WHERE user_id IN (SELECT * FROM mydb GROUP BY user_id, num HAVING COUNT(*) > 1)
returns a syntax error.
This is what I expect:
Example:
id user_id num
1 1 1
2 1 1
3 2 1
4 1 2
5 2 2
In this example id 1 and 2 have both columns (user_id and num) of the same value so they should be removed. Preferably, but not necessarily I would like to have a solution that would leave only one such row (doesn't matter which one).
Result:
id user_id num
2 1 1
3 2 1
4 1 2
5 2 2
Note: id is a primary key. user_id is a foreign key. num is an INTEGER.
You were having a syntax error because your IN operator has a single value on the left (user_id) but a table of non-single-value rows in the right side (SELECT *). Compare like with like; WHERE user_id IN (SELECT user_id ...) to avoid it.
Anyway, here's a query to delete all-but-newest:
DELETE FROM mydb
WHERE id NOT IN (
SELECT MAX(id) FROM mydb
GROUP BY user_id, num
);
The subquery will return the highest id for every unique (user_id, num) combination. Then we just delete all the other rows. I.e. in your example, the subquery would return 2, 3, 4, 5 as "correct", which would result in deletion of row 1.
I have the following data set:
DATE CODE RANK PARTITION
? ABS 0 1
12/04/2014 RET 1 1
20/04/2014 RET 2 1
01/05/2014 ABS 2 1
13/05/2014 RET 2 1
01/06/2015 ABS 2 1
09/10/2015 RETk 2 1
? ABS 0 2
02/04/2015 RET 1 2
03/04/2015 RET 2 2
04/04/2015 ABS 2 2
05/04/2015 STT 3 2
06/04/2015 RETk 4 2
07/04/2015 RETk 4 2
RANK is the column I want to calculate in my SQL given the columns DATE, CODE AND the previous value of the same column. It's initialized here to 0.
The logic I want to implement is as follows:
If RANK-1 (previous row) IS NULL AND CODE = ABS THEN RANK = 0
If RANK-1 (previous row) IS NULL AND CODE <> ABS THEN RANK <- (RANK-1) + 1
If RANK-1 = 0 or 1 AND CODE = RET THEN RANK <- (RANK-1) + 1
If RANK-1 = 2 AND CODE = STT THEN RANK <- (RANK-1) + 1
If RANK-1 = 3 AND CODE = RETk THEN RANK <- (RANK-1) + 1
If CODE = ABS THEN RANK <- (RANK-1) (previous row)
Else 0
The Teradata release I am using is R14. The calculation is done on a partition basis as shown in the example above. I have added some more constraints in the model to make it clearer. In this example, if the current code is RET, I do not increase the rank until the previous one is 0 or 1. Similarly, If my current code is RETk, I do not increase the rank until the previous one is equal to 3, otherwise, I do not change the rank. I repeat the same process in the following partition and so on ...
I cannot figure out how to update the current column value given the previous one... I tried many logic implementation with OLAP functions without success.
Can anyone give me a hint?
Thank you very much for your help
You can always use a recursive query for tasks like this. But performance will be bad unless the number of rows per group is low.
First you need a way to advance to the next row, as the next row's date can't be calculated based on the current row's date you must materialize the data and add a ROW_NUMBER:
CREATE TABLE tab(dt DATE, CODE VARCHAR(10), rnk INT, part INT);
INSERT INTO tab( NULL,'ABS' ,0 , 1);
INSERT INTO tab(DATE'2014-04-12','RET' ,1 , 1);
INSERT INTO tab(DATE'2014-04-20','RET' ,2 , 1);
INSERT INTO tab(DATE'2014-05-01','ABS' ,2 , 1);
INSERT INTO tab(DATE'2014-05-13','RET' ,2 , 1);
INSERT INTO tab(DATE'2014-06-01','ABS' ,2 , 1);
INSERT INTO tab(DATE'2014-10-09','RETk',2 , 1);
INSERT INTO tab( NULL,'ABS' ,0 , 2);
INSERT INTO tab(DATE'2015-04-02','RET' ,1 , 2);
INSERT INTO tab(DATE'2015-04-03','RET' ,2 , 2);
INSERT INTO tab(DATE'2015-04-04','ABS' ,2 , 2);
INSERT INTO tab(DATE'2015-04-05','STT' ,3 , 2);
INSERT INTO tab(DATE'2015-04-06','RETk',4 , 2);
INSERT INTO tab(DATE'2015-04-07','RETk',4 , 2);
CREATE VOLATILE TABLE vt AS
(
SELECT dt, code, part
-- used to find the next row
,ROW_NUMBER() OVER (PARTITION BY part ORDER BY dt) AS rn
FROM tab
) WITH DATA
PRIMARY INDEX(part, rn)
ON COMMIT PRESERVE ROWS
;
And now it's just applying your logic using CASE row after row:
WITH RECURSIVE cte (dt, code, rnk, part, rn) AS
(
SELECT
dt
,code
,CASE WHEN code = 'ABS' THEN 0 ELSE 1 END
,part
,rn
FROM vt
WHERE rn = 1
UNION ALL
SELECT
vt.dt
,vt.code
,CASE
WHEN cte.rnk IN (0,1) AND vt.CODE = 'RET' THEN cte.rnk + 1
WHEN cte.rnk = 2 AND vt.CODE = 'STT' THEN cte.rnk + 1
WHEN cte.rnk = 3 AND vt.CODE = 'RETk' THEN cte.rnk + 1
WHEN vt.CODE = 'ABS' THEN cte.rnk
ELSE cte.rnk
END
,vt.part
,vt.rn
FROM vt JOIN cte
ON vt.part =cte.part
AND vt.rn =cte.rn + 1
)
SELECT *
FROM cte
ORDER BY part, dt;
But I think your logic is not actually like this (based on the previous rows exact RANK value), you're just stuck in procedural thinking :-)
You might be able to do what you want using OLAP-functions only...
Something along the lines of:
create table table1
(
datecol date,
code varchar(10),
rankcol integer
);
--insert into table1 select '2014/05/13', 'RETj', 0;
select
case
when s1.code='ABS' and s2.rankcol = 1 then 1
when s1.code='RET' and s2.rankcol = 0 then 1
when s1.code='RET' and s2.rankcol = 1 then 2
else 0
end RET_res,
s1.*, s2.*
from
(select rankcol, code, row_number() OVER (order by datecol) var1 from table1) s1,
(select rankcol, code, row_number() OVER (order by datecol) var1 from table1) s2
where s1.var1=s2.var1-1
order by s1.var1
;
I am trying to flag the occurrences of a data item in column [Customer] determined by column [Division] and set three values for it in column [flag]. If data item [Customer] has both ‘Q’ and ‘Z’ data item values for column [Division] in separate rows I want the value of the data item [flag] set to 2 for every repeated occurrence of data item [Customer] where customer is a member of both ‘Q’ AND ‘Z’ Division. If this condition exists I want the value of the [flag] column equal to 2 for all rows where the [Customer] column value occurs. If data item value [Division] for [Customer] is only ‘Q’ then set [flag] to 1 and if data item value [Division] for [Customer] is only ‘Z’ then set [flag] to 0. There are thousands of possible values for the [Customer] column data item and multiple rows can contain the desired [customer] / [flag] combinations. How would I create column [flag] in the example below?
I want Customer separated by unique values. Notice Customer X is repeated 3 times and Customer A is repeated twice and the value in the [flag] column for each is 2 - ALL [flag] values where a customer is repeated In a row is 2.
DESIRED RESULTS:
Customer Rep division Count
A : 1 : Q : 1
B : 2 : Z : 0
X : 3 : Q : 2
X : 4 : Z : 2
X : 4 : Q : 2
D : 5 : Z : 0
S : 3 : Q : 2
H : 4 : Q : 1
S : 4 : Z : 2
Try this based on your expanded explanation:
CASE count(distinct [division] for [Customer])
WHEN 2 THEN 2
WHEN 1 AND [division] = 'Q' THEN 1
WHEN 1 AND [division] = 'Z' THEN 0
END
We count the distinct values of 'division' for every value of 'Customer'. If the count is 2 we know that both 'Q' and 'Z' are represented and we output the integer 2. If the count is 1 and the value of 'division' is 'Q' then we output 1. Lastly, if the count is 1 and 'division' is 'Z' then we output 0.
Assuming 'Q' and 'Z' are the only possible values for 'division' you can safely change the last test to: ELSE 0 to simplify. I included the full logic for clarity.