I have some sample data below and I want to use row_number but make it start when the value is 0 for col3
I have tried the below but it doesn't work
row_number() over (partition by col1,col2, case when col3 = 0 then 1 end order by col4 desc) as row2
Col1
col2
col3
col4
row_number (output wanted)
abc
def
7
500
abc
def
0
300
1
abc
def
1
200
abc
def
0
2
2
abc
def
4
30
Have NULL for others
case when col3 = 0
then row_number() over (partition by col1,col2, col3 order by col4 desc) end as row2
A row number is just a running count of rows. So you should be able to do this:
select
col1, col2, col3, col4,
count(case when col3 = 0 then 1 end)
over (partition by col1, col2 order by col4 desc, ctid) as row2
from ...
order by col1, col2, col4 desc, ctid;
I have added Postgre's internal CTID in order to get a deterministic order for the case of duplicate col4 values. If such duplicates are not possible, you can remove CTID from the ORDER BY clause.
Thanks guys but I just figured it out.
I did
case when col3 =0 then row_number() over (partition by col1,col2,col3=0 order by col4 desc) else null end as Row
so what this did was a running count for both sets of 0 and non0 and I'm just hiding the non 0 ones with the case.
Related
I have a task where I need to order the results of query in a way, that the highest of 3 values gets displayed in the first column after the ID, the second highest in the middle one and the smallest in the last column.
The tables look like this:
ID
Col1
Col2
Col3
1234
30
50
40
2345
40
30
60
3456
60
50
40
And the result should look like this:
ID
Col1
Col2
Col3
1234
50
40
30
2345
60
40
30
3456
60
50
40
The values are package dimensions which need to be in order to be processed.
Thank you in advance :)
This is pretty simple using apply:
select t.*, v.*
from t outer apply
(select max(case when seqnum = 1 then col end) as col1,
max(case when seqnum = 2 then col end) as col2,
max(case when seqnum = 3 then col end) as col3
from (select v.col,
row_number() over (order by v.col desc) as seqnum
from (values (t.col1), (t.col2), (t.col3)
) v(col)
) v
) v;
SQL Server is quite efficient when using APPLY within a single row. I would expect the performance to be comparable to a bunch of complex case expressions. In addition, this gives more flexibility if any of the values are NULL.
And, it is much easier to expand to more columns!
Unfortunately, there is no simple and short way of achieving this.
Try below query:
select
case when col1 > col2 and col1 > col3 then col1
else case when col2 > col1 and col2 > col3 then col2
else col3 end end,
case when (col1 > col2 and col1 < col3) or (col1 < col2 and col1 > col3) then col1
else case when (col2 > col1 and col2 < col3) or (col2 < col1 and col2 > col3) then col2
else col3 end end,
case when col1 < col2 and col1 < col3 then col1
else case when col2 < col1 and col2 < col3 then col2
else col3 end end
from tbl
SQL fiddle
You may also unpivot it, sort the value and then pivot it back
SELECT *
FROM
(
SELECT t.id, v.col,
col_no = row_number() over (partition by t.id order by v.col desc)
FROM yourtable t
CROSS APPLY
(
VALUES (col1), (col2), (col3)
) v (col)
) d
PIVOT
(
MAX(col)
for col_no in ([1], [2], [3])
) p
the question is not clear but you can use a temp table. First, read the top 3 of data with ordering highest, secondly do it same again with offset value 3, 6 and third times order by lowest.
push the results after each step
read the temp table
I have a table that looks like this:
Column1 | Column2 | Column3| Column4
4 | 3 | 2 | 1
2 | 1
3 | 2 | 1
I want to flip the columns so that 1 always start in column 1 and then the rest of the values follow to the right. Like this:
Column1 | Column2 | Column3 | Column4
1 | 2 | 3 | 4
1 | 2
1 | 2 | 3
This is an example table. The real table is a hierarchy of a company so 1 = CEO and 2 = SVP for example. 1 is always the same name but as the number gets higher (lower in chain of command) the more names that are in that level. I'm hoping for an automated solution that looks for 1, makes that the first column and then populates the columns. I am struggling because the value that 1 represents is in different columns so I can't just change the order of the columns.
I was able to accomplish this using VBA but I would prefer to keep it in SQL.
I don't have any useful code that I have tried so far.
You can use Case expression:
WITH CTE1 AS
(SELECT 4 AS COL1, 3 AS COL2 , 2 AS COL3, 1 AS COL4 FROM DUAL
UNION ALL
SELECT 2, 1, NULL, NULL FROM DUAL
UNION ALL
SELECT 3, 2, 1, NULL FROM DUAL
)
SELECT CASE WHEN COL1 <> 1 THEN 1 ELSE COL1 END AS COL1,
CASE WHEN COL2 <> 2 THEN 2 ELSE COL2 END AS COL2,
CASE WHEN COL3 <> 3 THEN 3 ELSE COL3 END AS COL3,
CASE WHEN COL4 <> 4 THEN 4 ELSE COL4 END AS COL4
FROM CTE1;
You can apply some CASEes checking all possibilities, this is assuming NULLs for missing data:
COALESCE(col4,col3,col2,col1) AS c1,
CASE
WHEN col4 IS NOT NULL THEN col3
WHEN col3 IS NOT NULL THEN col2
WHEN col2 IS NOT NULL THEN col1
END AS c2,
CASE
WHEN col4 IS NOT NULL THEN col2
WHEN col3 IS NOT NULL THEN col1
END AS c3,
CASE
WHEN col4 IS NOT NULL THEN col1
END AS c4
You want to sort the values. A generic SQL solution would use:
select max(case when seqnum = 1 then col end) as col1,
max(case when seqnum = 2 then col end) as col2,
max(case when seqnum = 3 then col end) as col3,
max(case when seqnum = 4 then col end) as col4
from (select col1, col2, col3, col4, col,
row_number() over (order by col) as seqnum
from ((select col1 as col, 1 as which, col1, col2, col3, col4 from t) union all
(select col2 as col, 2 as which, col1, col2, col3, col4 from t) union all
(select col3 as col, 3 as which, col1, col2, col3, col4 from t) union all
(select col4 as col, 4 as which, col1, col2, col3, col4 from t)
) t
where col is not null
) t
group by col1, col2, col3, col4;
This would be simpler in a database that supports lateral joins. And a unique id on each row would also help.
We are trying to get a group by result by checking the next rows value.
Sample Data:
Table A
COL1 COL2 COL3
---- ---- ----
B BUY 1
B SELL 1.2
B SELL 2
C BUY 3
C SELL 4
C BUY 5
Result:
COL1 COL2 COUNT(1)
---- ---- --------
B BUY 1
B SELL 2
C BUY 1
C SELL 1
C BUY 1
You appear to have ordered by COL3; if this is the case then:
SELECT col1,
col2,
change - COALESCE( LAG( change ) OVER ( PARTITION BY col1 ORDER BY change ), 0 )
AS cnt
FROM (
SELECT col1,
col2,
CASE LEAD( col2 ) OVER ( PARTITION BY col1 ORDER BY col3 )
WHEN col2
THEN NULL
ELSE ROW_NUMBER() OVER ( PARTITION BY col1 ORDER BY col3 )
END AS change
FROM a
)
WHERE change IS NOT NULL;
If I understand correctly, you can do this with a difference of row numbers approach:
select col1, col2, count(*)
from (select t.*,
row_number() over (partition by col1 order by col3) as seqnum,
row_number() over (partition by col1, col2 order by col3) as seqnum_2,
from t
) t
group by col1, col2, (seqnum - seqnum_2);
This identifies groups of adjacent col2 values based on the ordering in col3.
I have an output of some part of my stored proedure like this:
col1 col2 col3 col4
--------------------------
2016-05-05 1 2 2
2016-05-05 1 3 32
2016-05-12 2 1 11
2016-05-12 3 1 31
Now I need to get result based on this condition
col2 = 1 and col3 = max or col3 = 1
and col2 = max
The final result should be
col1 col2 col3 col4
-------------------------
2016-05-05 1 3 32
2016-05-12 3 1 31
Not sure if thats the most efficient way , but you can use ROW_NUMBER() :
SELECT * FROM (
SELECT t.*,
ROW_NUMBER() OVER(PARTITION BY t.col1 ORDER BY t.col3 DESC) as rnk,
WHERE t.col2 = 1
UNION ALL
SELECT t.*,
ROW_NUMBER() OVER(PARTITION BY t.col1 ORDER BY t.col2 DESC) as rnk,
WHERE t.col3 = 1) tt
WHERE rnk = 1
This will give you all the records with
(col2=1 and col3=max) or (col3=1 and col2=max)
This is a bit tricky. Your data has no ambiguities, such as duplicate maximuma in col4 or "1" values in both col2 and col3.
The following is a direct translation of the logic in your question:
select t.*
from t
where t.col4 = (select max(t2.col4)
from t t2
where t2.col1 = t.col1 and (t2.col2 = 1 or t2.col3 = 1)
);
Try this. Note if there are more than 1 same max value, then you need all of those in output. And it will work for all scenarios, even when col1 is not in sync with col2 and col3.
I am first finding highest values of col2 and col3 and assigning them value as 1. Then in outer query, I am using your join condition. Demo created for Postgres DB as SQLServer wasn't available.
SQLFiddle Demo
select col1,col2,col3,col4
from
(
select t.*,
RANK() OVER(ORDER BY col3 DESC) as col3_max,
RANK() OVER(ORDER BY col2 DESC) as col2_max
from your_table t
) t1
where
(col2=1 and col3_max=1)
OR
(col3=1 and col2_max=1)
Alternative way:
SELECT * FROM (
SELECT *, ROW_NUMBER() OVER (PARTITION BY col1 ORDER BY iif(col2 = 1, col3, col2) DESC) as r
FROM tbl) t
WHERE r = 1
This should be simple but for some reason I'm stuck. Consider the following data:
KEY1 KEY2 COL1 COL2 COL3
--------------------------------------
1 1 A 7 (null)
1 2 A 8 (null)
1 3 (null) 7 (null)
2 2 (null) (null) 4
2 4 B 6 (null)
3 1 A B (null)
(KEY1 is the Id, KEY2 is the generation, and there are actually about 30 data columns but I'm only listing 3 here for simplicity.)
I want to get one row per Id, and for each column get the last non-null value. In other words...
KEY1 COL1 COL2 COL3
----------------------------
1 A 7 (null)
2 B 6 4
3 A B (null)
I tried the following but it seems to do nothing other than echo out all my rows.
SELECT key1,
LAST_VALUE(col1) OVER (PARTITION BY key1 ORDER BY key2 ASC) AS col1,
LAST_VALUE(col2) OVER (PARTITION BY key1 ORDER BY key2 ASC) AS col2,
LAST_VALUE(col3) OVER (PARTITION BY key1 ORDER BY key2 ASC) AS col3
FROM test1
(And this is for SQL Server 2012 and SQL Server Express.)
SQL Server does not (yet) support the IGNORE NULL option on window functions. One method is to use conditional aggregation. This requires an intelligent generation of sequence numbers for the columns, to ensure that the value "1" for the sequence is assigned to non-NULL values.
Here is a query that should do this:
select t1.key1,
max(case when seqnum1 = 1 then col1 end) as col1,
max(case when seqnum2 = 1 then col2 end) as col2,
max(case when seqnum3 = 1 then col3 end) as col13
from (select t1.*,
row_number() over (partition by key1
order by (case when col1 is not null then 1 else 2 end),
key2 desc
) as seqnum1,
row_number() over (partition by key1
order by (case when col2 is not null then 1 else 2 end),
key2 desc
) as seqnum2,
row_number() over (partition by key1
order by (case when col3 is not null then 1 else 2 end),
key2 desc
) as seqnum3
from test1 t1
) t1
group by t1.key1
If I understood the requirements correctly, shouldn't this work? Might be quite expensive depending on the amount of data / columns.
select
key1,
(select top 1 col1 from test1 t2 where t.key1 = t2.key1 and col1 is not null order by key2 desc) as col1,
(select top 1 col2 from test1 t2 where t.key1 = t2.key1 and col2 is not null order by key2 desc) as col2,
(select top 1 col3 from test1 t2 where t.key1 = t2.key1 and col3 is not null order by key2 desc) as col3
from
(select distinct key1 from test1) t