Order By using case with conditional results and partition row_number() - sql-server

I have a SQL that I've not been able to return the order correctly. Below is example of the rows and the order I want them to appear in. I tried ORDER BY WITH CONDITIONAL CASE AND ROW_NUMBER OVER PARTION without success. I want ColA to be the primary sort and ColB secondary only when ColC has a length < 3 otherwise ColB is primary and ColA is secondary
ColA ColB ColC
5 750 15
5 750 15
3 984 13
3 984 13
5 1021 15
5 1021 15
4 1602 14
4 1602 14
4 1823 14
4 1823 14
6 4099 16
6 4099 16
11 4099 240990
0 10880 10
0 10880 10
3 10881 13
3 10881 13
2 11053 12
8 11053 211053
6 10891 16
6 10891 16
2 11034 12
10 11034 211034
ColA ColB ColC
0 10880 10
0 10880 10
2 11034 12
10 11034 211034
2 11053 12
8 11053 211053
3 984 13
3 984 13
3 10881 13
3 10881 13
4 1602 14
4 1602 14
4 1823 14
4 1823 14
5 750 15
5 750 15
5 1021 15
5 1021 15
6 4099 16
6 4099 16
11 4099 240990
6 10891 16
6 10891 16

order by case when len(ColC) < 3 then ColA else ColB end,
case when len(ColC) < 3 then ColB else ColA end
SQL Fiddle Example

Related

Data Format in SQL Server

I have data as below :
Month and then corresponding units sold for 3 different item type
Month Sale1 Sale2 Sale3
1 20
2 12
3 50
1 2
2 17
3 56
1 11
2 35
3 9
I want data to be in below format:
Month Sale1 Sale2 Sale3
1 20 2 11
2 12 17 35
3 50 56 9
Maybe SUM is better then MAX if there can be items from one type across different months:
SELECT [Month]
,SUM(Sale1) AS Sale1
,SUM(Sale2) AS Sale2
,SUM(Sale3) AS Sale3
FROM [table]
GROUP BY [Month]

Advanced sql with windowing claus

SELECT a.*,
SUM(s.amount) over(ORDER BY s.month rows unbounded preceding) AS a ,
SUM(s.amount) over(PARTITION BY s.month ORDER BY s.month rows unbounded preceding) AS b,
SUM(s.amount) over(PARTITION BY s.month ) AS c_1,
SUM(s.amount) over(PARTITION BY s.month ORDER BY s.month rows BETWEEN unbounded preceding AND unbounded following) AS c,
SUM(s.amount) over(PARTITION BY s.month ORDER BY s.month rows BETWEEN 1 preceding AND unbounded following) AS d,
SUM(s.amount) over(PARTITION BY s.month ORDER BY s.month rows BETWEEN 1 preceding AND 1 following) AS e,
SUM(s.amount) over(PARTITION BY s.month ORDER BY s.month rows BETWEEN unbounded preceding AND 1 following) AS f,
SUM(s.amount) over(PARTITION BY s.month ORDER BY s.month rows CURRENT ROW) AS g
FROM all_sales s,
(SELECT *
FROM all_sales) a
WHERE s.rowid = a.rowid;
/
--above query give the result shown below what is difference between c_1 and c column.
YEAR MONTH PRD_TYPE_ID EMP_ID AMOUNT A B C_1 C D E F G
1 2006 1 1 21 1.00 1 1 10 10 10 3 3 1
2 2006 1 1 21 2.00 3 3 10 10 10 6 6 2
3 2005 1 2 21 3.00 6 6 10 10 9 9 10 3
4 2005 1 2 22 4.00 10 10 10 10 7 7 10 4
5 2006 2 1 21 5.00 15 5 11 11 11 11 11 5
6 2005 2 1 21 6.00 21 11 11 11 11 11 11 6
7 2005 3 1 21 21 7 7 7 7 7
8 2006 3 2 21 7.00 28 7 7 7 7 7 7 7
9 2005 4 1 21 8.00 36 8 17 17 17 17 17 8
10 2006 4 2 21 9.00 45 17 17 17 17 17 17 9
11 2006 5 2 21 45 10 10 10 10 10
12 2005 5 1 21 10.00 55 10 10 10 10 10 10 10
13 2006 6 1 21 11.00 66 11 23 23 23 23 23 11
14 2005 6 1 21 12.00 78 23 23 23 23 23 23 12
15 2005 7 2 21 13.00 91 13 27 27 27 27 27 13
16 2006 7 1 21 14.00 105 27 27 27 27 27 27 14
17 2005 8 2 21 15.00 120 15 31 31 31 31 31 15
18 2006 8 1 21 16.00 136 31 31 31 31 31 31 16
19 2005 9 2 21 17.00 153 17 35 35 35 35 35 17
20 2006 9 1 21 18.00 171 35 35 35 35 35 35 18
21 2005 10 2 21 19.00 190 19 39 39 39 39 39 19
22 2006 10 1 21 20.00 210 39 39 39 39 39 39 20
23 2006 11 1 21 21.00 231 21 43 43 43 43 43 21
24 2005 11 1 21 22.00 253 43 43 43 43 43 43 22
25 2006 12 2 21 23.00 276 23 47 47 47 47 47 23
26 2005 12 1 21 24.00 300 47 47 47 47 47 47 24
You have the same result because your statements are preaty the same:
SUM(s.amount) over(PARTITION BY s.month ) AS c_1,
SUM(s.amount) over(PARTITION BY s.month ORDER BY s.month rows BETWEEN unbounded preceding AND unbounded following) AS c
The cause of it is condition BETWEEN unbounded preceding AND unbounded following because it covers the entire range of partition.
FROM MSDN:
UNBOUNDED PRECEDING - Specifies that the window starts at the first row of the partition. UNBOUNDED PRECEDING can only be specified as window starting point.
UNBOUNDED FOLLOWING - Specifies that the window ends at the last row of the partition. UNBOUNDED FOLLOWING can only be specified as a window end point. For example RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING defines a window that starts with the current row and ends with the last row of the partition.
When together they are equal to PARTITION BY s.month

SQL Server 2008 R2: Recursive query

This is the follow up question of : Prepare a recursive query
I have the table with the two columns namely cola and colb as shown below:
Table : Test
create table Test
(
cola int,
colb int
);
Records I have entered are:
Cola Colb
------------
1 2
1 3
1 4
2 5
2 6
2 3
3 2
3 4
3 7
3 10
10 11
11 12
11 13
11 14
12 15
13 16
14 99
15 88
16 77
Note: Now I want to show the only records who are connected with value I have pass. For example If I pass the value as 1 then it should display me the connected number to it and form connect like a tree.
For the above requirement I have got the script from Dark Knight as shown below which works fine.
;WITH CTE AS
(
SELECT COLA,COLB,','+CAST(COLA AS VARCHAR(MAX))+',' AS CHCK FROM test WHERE COLA=1
UNION ALL
SELECT C1.COLA,C1.COLB,C.CHCK+CAST(C1.cola AS VARCHAR(MAX))+','
FROM CTE C INNER JOIN test C1 ON C.colb = C1.cola
WHERE CHARINDEX(','+CAST(C.colb AS VARCHAR(MAX))+',',C.CHCK)=0
),
OUTERCTE AS
(
SELECT DISTINCT COLA,COLB,ROW_NUMBER() OVER(PARTITION BY Colb ORDER BY Cola) rn FROM CTE --ORDER BY COLA
)
SELECT Cola,Colb FROM OUTERCTE
WHERE rn<=1
ORDER BY CASE WHEN Cola = 1 THEN 1 ELSE 2 END;
Which gives me this:
----------------
Cola Colb
----------------
1 2
1 3
1 4
2 5
2 6
3 7
3 10
10 11
11 12
11 13
11 14
12 15
13 16
16 77
15 88
14 99
Requirement: Now I want to show the levels of records.
Expected Result:
------------------------------
Cola Colb Level
------------------------------
1 2 1
1 3 1
1 4 1
2 5 2
2 6 2
3 7 2
3 10 2
10 11 3
11 12 4
11 13 4
11 14 4
12 15 5
13 16 5
16 77 6
15 88 6
14 99 5
;WITH CTE AS
(
SELECT COLA,COLB
,','+CAST(COLA AS VARCHAR(MAX))+',' AS CHCK
, 1 as lvl FROM #Test WHERE COLA=1
UNION ALL
SELECT C1.COLA,C1.COLB ,C.CHCK+CAST(C1.cola AS VARCHAR(MAX))+','
, c.lvl+1
FROM CTE C INNER JOIN #Test C1 ON C.colb = C1.cola
WHERE CHARINDEX(','+CAST(C.colb AS VARCHAR(MAX))+',',C.CHCK)=0
),
cte2 as (
select * , ROW_NUMBER() over (partition by colb order by lvl)as rn From CTE
)
select cola,colb,lvl from cte2 where rn = 1

Merge two tables while dragging one column from one table to the other

With Sql Server 2014:
I have two tables - Events and Locations, that share a time column and I need to merge them into one table order by time. In the Events table there is an Event column that I need to place in all the Locations row following that event (time wise), here is an example:
Events:
time event
------------
09:00 2
09:10 3
10:15 1
10:17 2
10:30 3
Locations:
time X Y
-------------
09:01 1 3
09:02 2 3
09:05 4 1
09:09 6 4
09:10 7 8
09:11 8 8
09:12 9 7
10:17 1 2
10:19 5 4
10:20 4 3
10:25 5 4
10:28 3 5
Merged Table:
time X Y event
--------------------
09:00 0 0 2
09:01 1 3 2 <
09:02 2 3 2 <
09:05 4 1 2 <
09:09 6 4 2 <
09:10 0 0 3
09:10 7 8 3 <
09:11 8 8 3 <
09:12 9 7 3 <
10:15 0 0 1
10:17 0 0 2
10:17 1 2 2 <
10:19 5 4 2 <
10:20 4 3 2 <
10:25 5 4 2 <
10:28 3 5 2 <
10:30 0 0 3
The elements that mark with '<' are the inserted Events.
Any ideas and help on how to perform this task is welcome.
You can use UNION ALL and APPLY:
SQL Fiddle
SELECT
[Time], X = 0, Y = 0, [Event]
FROM [Events]
UNION ALL
SELECT l.*, x.Event
FROM Locations l
CROSS APPLY(
SELECT TOP 1 *
FROM [Events]
WHERE [Time] <= l.[Time]
ORDER BY [Time] DESC
)x
ORDER BY [Time]

Dynamically add a groupid and find the distinct count sql server 2008

Source Data:
TID Pid OpID
1 41 1
1 41 2
1 44 1
1 69 1
1 248 1
1 255 1
1 255 2
4 41 1
4 41 2
4 44 1
4 69 1
4 248 1
4 255 1
4 255 2
6 41 1
6 44 1
6 69 1
6 248 1
6 255 1
6 255 2
15 41 1
15 248 1
15 255 1
15 255 2
16 41 1
16 248 1
16 255 1
16 255 2
output:
Pid OpID Unique TId_count
41 1 2
41 2 2
44 1 2
69 1 2
248 1 2
255 1 2
255 2 2
41 1 1
44 1 1
69 1 1
248 1 1
255 1 1
255 2 1
41 1 2
248 1 2
255 1 2
255 2 2
Rules:
1) At first i need to find what are the available PID and OperationID for each TID
2) later consider PID and OPID as a set(group) and find the possible combination of TID and display distinct TID count
Example:
i) for the PID {41,41,44,69,248,255,255} and OperationId {1,2,1,1,1,1,2} is falling in two tester {1,4} so I need the output TID count is 2.
ii) for the PID {41,44,69,248,255,255} and OperationId {1,1,1,1,1,2} is falling in single tester {6} so i need the output TID count is 1.
iii) Finally, for the PID {41,248,255,255} and OperationId {1,1,1,2} is falling in two tester {15,16} so i need the output TID count is 2.
I cannot imagine any use for this ... but check out this anyway:
select pid, opid, count(*) from
(select tid, pid, opid,
(SELECT ',' + cast(x.pid as nvarchar(10))
FROM #temp x
WHERE x.tid = t.tid
FOR XML PATH ('')) as PidGroup,
(SELECT ',' + cast(x.OpId as nvarchar(10))
FROM #temp x
WHERE x.tid = t.tid
FOR XML PATH ('')) as OpIdGroup
from #temp t) innerselect
group by pid, opid, PidGroup, opidgroup
it produces the output you want ... just replace #temp with your tablename.

Resources