In SQL Server, Split bit column to 2 columns using PIVOT - sql-server

I have a table as below
Name Grade SubjectAorB
Pooja B 1
Preeti C 0
Preeti C 1
Chintu A 1
Deepika B 0
Deepika B 1
Peter A 0
John A 0
Last column SubjectAorB has values as 0 and 1. 0 means Subject A and 1 means Subject B. A student can have either of the subject or both. I want output as below:
Name Grade Subject A Subject B
Pooja B 0 1
Preeti C 1 1
Chintu A 0 1
Deepika B 1 1
Peter A 1 0
John A 1 0

You can do this using conditional aggregation:
SELECT
Name,
Grade,
SubjectA = MAX(CASE WHEN SubjectAorB = 0 THEN 1 ELSE 0 END),
SubjectB = MAX(CASE WHEN SubjectAorB = 1 THEN 1 ELSE 0 END)
FROM #tbl
GROUP BY Name, Grade

Related

SUM values when conditions met

I have the following SQL Server table with the following data:
PRICE(decimal 9,2) PRICETYPE(int) EVENTDETAILID (int)
PRICE PRICETYPE EVENTDETAILID
------------------------------------------------
99 1 1
99 1 1
99 1 1
15 0 1
15 0 1
50 1 2
50 1 2
I want to SUM the PRICE of the results with the following conditions:
for each EVENTDETAILID, SUM every line with a pricetype is 0 and for every line per EVENTDETAILID pricetype is 1, then add it only 1 time.
For the above example the required output would be:
99 + 15 + 15 for eventDetailId = 1
50 for eventDetailsId = 2
I've tried the following but doesn't work as expected as I'm not able to add PRICE only once if PRICETYPE is 1:
SELECT
SUM(PRICE)
FROM
ReservationDetails
GROUP BY
eventDetail_id
You may phrase this as an aggregation (GROUP BY) query over the event detail ID. The sum can be broken into a conditional sum when the detail ID is 0, combined with the maximum price when the detail ID is 1. Since you told us that the price is always the same when PRICETYPE=1, therefore we can choose any single value.
SELECT
EVENTDETAILID,
SUM(CASE WHEN PRICETYPE = 0 THEN PRICE ELSE 0 END) +
MAX(CASE WHEN PRICETYPE = 1 THEN PRICE ELSE 0 END) AS total
FROM yourTable
GROUP BY
EVENTDETAILID
ORDER BY
EVENTDETAILID;
Demo

Union and Order By (SQL Server)

Consider a table A and table B like :
Table A:
debit credit row
-----------------------
10 0 1
0 10 1
20 0 2
0 20 2
30 0 3
0 30 3
Table B:
debit credit row
-----------------------
10 0 1
0 10 1
20 0 2
0 20 2
30 0 3
0 30 3
Result:
debit credit row
--------------------
10 0 1
20 0 2
30 0 3
0 10 1
0 20 2
0 30 3
I'm trying to union all table A, B and show debit first, then sort it by row column.
by definition, the individual SELECTs making up a UNION are not allowed to contain an ORDER BY clause. The only ORDER BY clause allowed is at the end of the UNION and it applies to the entire UNION, making xxx UNION yyy ORDER BY zzz the eqivalent of (xxx UNION yyy) ORDER BY zzz
Meaning:
Invalid:
Select debit,credit,row
from
(
Select debit,credit,row
From table a
Where 'condition'
Union
Select debit,credit,row
From table b
Where 'condition 2'
) results
order by debit, row
Valid:
Select debit,credit,row
From table a
Where 'condition'
Union
Select debit,credit,row
From table b
Where 'condition 2'
Order by debit, row

SQL: To obtain single record for each CourseId

I'm naive to SQL...pls help me with my below query:
I have a table named Course as shown below:
Key CourseName CourseId IsCurrentVersion
0 Course_1 A 0
1 Course_1 A 0
2 Course_1 A 1
3 Course_2 B 0
4 Course_2 B 0
5 Course_3 C 1
6 Course_4 D 0
7 Course_5 E 0
8 Course_5 E 0
9 Course_6 F 1
10 Course_6 F 1
11 Course_6 F 1
12 Course_7 G 1
13 Course_7 G 0
14 Course_7 G 0
I want the below result set:
CourseName CourseId IsCurrentVersion
Course_1 A 1
Course_2 B 0
Course_3 C 1
Course_4 D 0
Course_5 E 0
Course_6 F 1
Course_7 G 1
For records having same CourseId; IsCurrentVersion having 1 should be preferred to 0. Single records should also get displayed in output irrespective of their IsCurrentVersion values.
Database is SQL Server 2008.
Try this:
SELECT CourseName, CourseId, IsCurrentVersion
FROM Course AS A
WHERE IsCurrentVersion = (SELECT MAX(IsCurrentVersion)
FROM Course AS B
WHERE A.CourseId = B.CourseId)
GROUP BY CourseName, CourseID, IsCurrentVersion
This should get you what you are looking for, assuming the only values for IsCurrentVersion are 1 and 0.
SELECT CourseName, CourseId, MAX(IsCurrentVersion)
FROM Course
GROUP BY CourseName, CourseID
If the IsCurrentVersion column is a bit and not an integer, use this instead.
SELECT CourseName, CourseId, MAX(CASE WHEN IsCurrentVersion = 1 THEN 1 ELSE 0 END)
FROM Course
GROUP BY CourseName, CourseID

Combine multiple rows into one row with same number of columns

I have results that have multiple rows for priority counts for specific locations. I would like to simply turn those results into a single row to display the same information.
My current code is:
SELECT t.city_nm as CITY
,sum(case when h.priority = 1 then 1 else 0 end)as Priority1
,sum(case when h.priority = 2 then 1 else 0 end)as Priority2
,sum(case when h.priority = 3 then 1 else 0 end)as Priority3
from SHIPMENT h
INNER JOIN PET_EVT_LOG e
on h.svc_id = e.svc_id
INNER JOIN LOCATION t
ON t.city_id = e.term_id
INNER JOIN CUSTOMER u
ON h.ship_cust = u.cust_id
where u.cust_nm = 'CAL NATURAL'
and e.evt_cd = 'ARRIVAL'
and e.evt_dt_tm > date(current timestamp) - 7 day
GROUP BY t.city_nm, h.priority;
My results look like this:
CITY Priority1 Priority 2 Priority3
Atlanta 7 0 0
Atlanta 0 25 0
Atlanta 0 0 3
Baltimore 3 0 0
Baltimore 0 12 0
Baltimore 0 0 1
Detroit 9 0 0
Detroit 0 32 0
Detroit 0 0 5
Where there is a number count in one row, the other two fields are ALWAYS 0, so they should easily be combined to produce results that look like this:
CITY Priority1 Priority 2 Priority3
Atlanta 7 25 3
Baltimore 3 12 1
Detroit 9 32 5
try replacing
GROUP BY t.city_nm, h.priority;
by
GROUP BY t.city_nm;

Partition data into subgroups based on bit fields

I have the first 4 columns of data, and I wan't to use the Ranking functions in the SQL 2008 R2 to derive the fifth column. What's the best way to partition the data into subgroups based on the nextiteminsubgroup and previousiteminsubgroup fields?
Group OrderInGroup NextItemInSubGroup PreviousItemInSubGroup SubGroup
1 1 1 0 1
1 2 1 1 1
1 3 1 1 1
1 4 0 1 1
1 5 0 0 2
1 6 0 0 3
1 7 1 0 4
1 8 1 1 4
1 9 0 1 4
2 1 0 0 1
2 2 0 0 2
2 3 0 0 3
2 4 1 0 4
2 5 0 1 4
3 1 0 0 1
4 1 0 0 1
4 2 0 0 2
4 3 0 0 3
A recursive CTE solution:
DECLARE #t TABLE
([Group] INT
,OrderInGroup INT
,NextItemInSubGroup INT
,PreviousItemInSubGroup INT
,SubGroup INT
)
INSERT #t
VALUES
(1,1,1,0,1),(1,2,1,1,1),(1,3,1,1,1),(1,4,0,1,1),(1,5,0,0,2),(1,6,0,0,3),
(1,7,1,0,4),(1,8,1,1,4),(1,9,0,1,4),(2,1,0,0,1),(2,2,0,0,2),(2,3,0,0,3),
(2,4,1,0,4),(2,5,0,1,4),(3,1,0,0,1),(4,1,0,0,1),(4,2,0,0,2),(4,3,0,0,3)
;WITH recCTE
AS
(
SELECT [Group], OrderInGroup,NextItemInSubGroup , PreviousItemInSubGroup, 1 AS subgroup
FROM #t
WHERE OrderInGroup = 1
UNION ALL
SELECT r.[Group], t.OrderInGroup,t.NextItemInSubGroup , t.PreviousItemInSubGroup,
CASE WHEN r.NextItemInSubGroup = 1 THEN r.subgroup ELSE r.subgroup + 1 END
FROM recCTE AS r
JOIN #t AS t
ON t.[Group] = r.[Group]
AND t.OrderInGroup = r.OrderInGroup + 1
)
SELECT * FROM recCTE
ORDER BY [Group],OrderInGroup ;
P.S. it's best practice to avoid using SQL keywords (e.g. GROUP) as table/column names
Seems like 0 and 0 restart the ranking.
Select
Rank() Over (
Partition By
[Group]
, Case When [NextItemInSubGroup] + [PreviousItemInSubGroup] = 0
Then 0
Else 1
End
Order By [OrderInGroup]
) as [SubGroup]
From Your_Table;

Resources