SQL Server pivot using case statement - sql-server

I'm trying to pivot out some data and I think I need to incorporate a case statement in my pivot code but I'm not sure how. I have the table below:
ID AreaCode
1001 1501
1001 1502
1001 2301
1031 1010
1031 3012
1048 2304
1048 3012
1048 4022
The first digit of each AreaCode refers to a body area, I'm using the code below to indicate which body area is affected:
select id,
case when left(areaID,1)=1 then 'Yes' end Head,
case when left(areaID,1)=2 then 'Yes' end Face,
case when left(areaID,1)=3 then 'Yes' end Neck,
case when left(areaID,1)=4 then 'Yes' end Abdo
from #testcase
Which gives me the following:
id Head Face Neck Abdo
1001 Yes NULL NULL NULL
1001 Yes NULL NULL NULL
1001 NULL Yes NULL NULL
1031 Yes NULL NULL NULL
1031 NULL NULL Yes NULL
1048 NULL Yes NULL NULL
1048 NULL NULL Yes NULL
1048 NULL NULL NULL Yes
However, I need my output table to contain one row for each id, like so:
id Head Face Neck Abdo
1001 Yes Yes Null Null
1031 Yes Null Yes Null
1048 Null Yes Yes Yes
Can incorporate my case statement in a pivot to achieve this? Thanks

You need to use aggregate on top of case statements
SELECT id,
Max(CASE
WHEN LEFT(areaID, 1) = 1 THEN 'Yes'
END) Head,
Max(CASE
WHEN LEFT(areaID, 1) = 2 THEN 'Yes'
END) Face,
Max(CASE
WHEN LEFT(areaID, 1) = 3 THEN 'Yes'
END) Neck,
Max(CASE
WHEN LEFT(areaID, 1) = 4 THEN 'Yes'
END) Abdo
FROM #testcase
GROUP BY id

You could use a real PIVOT solution instead like this:
DECLARE #t table(ID int, AreaCode int)
INSERT #t
VALUES
(1001,1501),(1001,1502),(1001,2301),(1031,1010),
(1031,3012),(1048,2304),(1048,3012),(1048,4022)
SELECT id, [1]Head, [2]Face, [3]Neck, [4]Abdo
FROM
(
SELECT id, left(AreaCode, 1) Area, 'Yes' x
FROM #t
) p
PIVOT (Max(x) FOR [Area] IN ([1],[2],[3],[4])) AS pvt
Result:
id Head Face Neck Abdo
1001 Yes Yes NULL NULL
1031 Yes NULL Yes NULL
1048 NULL Yes Yes Yes

Related

Fill columns which have priority over other columns in SQL Server

I have a table like this:
id
mail_1
mail_2
mail_3
1
john
john_v2
john_v3
2
clarisse
NULL
clarisse_company
3
NULL
julie
NULL
4
mark
markus_91
NULL
5
alfred
NULL
NULL
And I would like to achieve that:
id
mail_1
mail_2
mail_3
1
john
john_v2
john_v3
2
clarisse
clarisse_company
NULL
3
julie
NULL
NULL
4
mark
markus_91
NULL
5
alfred
NULL
NULL
As you can see, if mail_2 or mail_3 are not null and mail_1 is null, mail_1 should be fulfilled. The thing here is if the id has two mails, this two mails must be in mail_1 and mail_2, not in mail_2 and mail_3 nor mail_1 and mail_3. If an id has just one mail, this mail must be in mail_1.
So the logic here is that mail_1 has priority over the other two, and mail_2 has priority over mail_3.
How could I achieve that in SQL Server (version 15)?
This should do. Just play by changing the values of the table variable below
declare #temp table(mail_1 varchar(20),mail_2 varchar(20),mail_3 varchar(20))
insert into #temp values(null,'middlename','lastname')
select coalesce(mail_1,mail_2,mail_3) as mail_1,
case when mail_1
is null and mail_2 is not null then mail_3
when mail_1
is not null and mail_2 is null
then
mail_3
else mail_2 end mail_2,
case when (mail_1 is null or mail_2 is null) then null else mail_3 end mail_3
from #temp

Need help in rewriting the query using CASE statement

SELECT distinct
ID,
LOWER(IFF(REGEXP_COUNT(pos_id, '^[0-9]+$')= 1, NULL, pos_id)) as pos
FROM table1
WHERE date='2022-02-02'
AND pos_id is not null
AND id='12345';
When I run the above query, I'm getting results like
ID
POS
12345
894f4bb2597f
But when I run the query below where I have used CASE, I'm getting NULL values as well as NOT NULL values.
SELECT distinct
ID,
CASE WHEN REGEXP_COUNT(pos_id, '^[0-9]+$')= 1 AND pos_id IS NOT NULL THEN NULL ELSE pos_id
END as pos
FROM table1
WHERE date='2022-02-02'
AND pos_id is not null
AND id='12345';
ID
POS
12345
894f4bb2597f
12345
NULL
For one ID, I'm getting NULL as well not NULL values.
I need to remove pos_id is not null in the WHERE clause and add that in CASE statement.
How to rewrite this query using CASE statement by removing the condition - pos_id is not null from the WHERE clause?
I tried the below query using CASE statement but not getting the correct results:
SELECT distinct
ID,
CASE when REGEXP_COUNT(pos_id,'^[0-9]+$')=1 and
pos_id is not null
THEN null else pos_id end
FROM table1
WHERE date='2022-02-02';
When I use CASE, I'm getting the count as 1,455,345 ROWS
but when I use - LOWER(IFF(REGEXP_COUNT(pos_id, '^[0-9]+$')= 1, NULL, pos_id
I'm getting COUNT as 2768 rows
so the key point of you question is the final sentence:
When I use CASE, I'm getting the count as 1,455,345 ROWS but when I use - LOWER(IFF(REGEXP_COUNT(pos_id, '^[0-9]+$')= 1, NULL, pos_id I'm getting COUNT as 2768 rows
So take your SQL and pushing it together with some input trying to understand "why the results are different" etc etc.
And really you are asking why do I how more distinct values when I don't to lower then then when I do.
The point is case sensitive counts will always be same or great than case insensitive counts.
SELECT
column2 as pos_id,
LOWER(IFF(REGEXP_COUNT(pos_id, '^[0-9]+$')= 1, NULL, pos_id)) as pos_i,
CASE
WHEN REGEXP_COUNT(pos_id, '^[0-9]+$') = 1 AND pos_id IS NOT NULL THEN NULL
ELSE pos_id
END as pos_c
,lower(pos_c) as lower_pos_c
,count(distinct pos_i) over() as IFF_rows_count
,count(distinct pos_c) over() as CASE_rows_count
,count(distinct lower_pos_c) over() as LOWER_CASE_rows_count
FROM VALUES
(12345, '894f4bb2597f'),
(12346, '1234'),
(12346, null),
(123, 'aaa'),
(123, 'Aaa'),
(123, 'aAa'),
(123, 'aaA');
POS_ID
POS_I
POS_C
LOWER_POS_C
IFF_ROWS_COUNT
CASE_ROWS_COUNT
LOWER_CASE_ROWS_COUNT
894f4bb2597f
894f4bb2597f
894f4bb2597f
894f4bb2597f
2
5
2
1234
null
null
null
2
5
2
null
null
null
null
2
5
2
aaa
aaa
aaa
aaa
2
5
2
Aaa
aaa
Aaa
aaa
2
5
2
aAa
aaa
aAa
aaa
2
5
2
aaA
aaa
aaA
aaa
2
5
2

How to get only a distinct row

I have a table which is shown on below
id locale roaming rent
301 NULL 18.00 NULL
300 NULL NULL 5.00
299 11.00 NULL NULL
298 NULL NULL 4.00
297 NULL 20.00 NULL
296 NULL NULL 6.00
295 9.00 NULL NULL
294 NULL 20.00 NULL
293 10.00 NULL NULL
I want to get only one value in each column (without id column) in a row. How can I do it? BUT I want to do it only in one select query.
A possible solution:
SELECT (
SELECT TOP 1 [local]
FROM tbl
WHERE [local] IS NOT NULL
ORDER BY [id] DESC
) AS [local]
,(
SELECT TOP 1 [roaming]
FROM tbl
WHERE [roaming] IS NOT NULL
ORDER BY [id] DESC
) AS [roaming]
,(
SELECT TOP 1 [rent]
FROM tbl
WHERE [rent] IS NOT NULL
ORDER BY [id] DESC
) AS [rent]
I do it so
DECLARE #locale AS DECIMAL(11,2)
DECLARE #roaming AS DECIMAL(11,2)
DECLARE #rent AS DECIMAL(11,2)
SELECT #locale=COALESCE(locale, #locale), #roaming=COALESCE(roaming, #roaming), #rent=COALESCE(rent, #rent) FROM my_table
SELECT #locale as locale, #roaming as roaming, #rent as rent

Count Days in SQL SERVER in Case When Clause

I have Table
1 2013-10-01 08:21 Null Null Null
1 2013-10-01 14:30 Null Null Null
2 2013-10-01 08:31 Null Lt Null
2 2013-10-01 14:31 EO Null Null
3 2013-10-01 14:30 EO Null Ab here
this Table is Result from this query
SELECT m.ID,L.Log_D,W.Sat,L.C,
(CASE WHEN convert(time,L.Log_D)>'08:31:00' and convert(time,L.Log_D)<'10:30:00' and L.C =1 then 'Lt'end )as Late,
(CASE WHEN convert(time,L.Log_D)<'13:30:00' and L.C =2 then 'Ab'end )as EarlyOut,
(CASE WHEN DATENAME(DAY, day( L.Log_D)) =2 THEN 'Ab' END) as Counte
from WorkPeriod W,LogT L,MinimumInfoT m where day(L.Log_D) =1
and month(L.Log_D) =10
and year(L.Log_D) =2013
and W.id=54
and m.Branch_ID=35
and L.C in(1,2)
and M.ID =L.EmpId
and W.id =m.W_Period
group by m.ID,L.Log_D,W.Sat,L.C
order by m.ID
I need the Absent Column Display as 'Ab' when the count Of the Day is less then 2 for each Id is that possible any help will be appreciated
You can use a Window Function to do this:
CASE WHEN COUNT(*) OVER (PARTITION BY m.ID) < 2 THEN 'ab' ELSE NULL END as Counte
This will get a count of records for each distinct m.ID. If the count for the current m.ID is less than 2, then it spits out ab.

Combining multiple rows in SQL with distinct identifier

I'm pulling some data from SQL Server from this table.
ID_Number Date_01 Date_02 Date_03 Date_04 Date_05
---------------------------------------------------------------------
1001 6/1/2015 6/5/2015 Null Null 6/6/2015
1001 Null Null 6/5/2015 Null 6/7/2015
1002 6/20/2015 Null Null 6/21/2015 Null
1002 6/21/2015 6/22/2015 6/23/2015 6/19/2015 6/20/2015
1003 6/25/2015 Null Null 6/26/2015 6/29/2015
I'm not sure what CTE query will I use to return only one row per ID and get the max date per column for each ID.
Here's the sample result:
ID_Number Date_01 Date_02 Date_03 Date_04 Date_05
----------------------------------------------------------------------
1001 6/1/2015 6/5/2015 6/5/2015 Null 6/7/2015
1002 6/21/2015 6/22/2015 6/23/2015 6/21/2015 6/20/2015
1003 6/25/2015 Null Null 6/26/2015 6/29/2015
You don't need CTE to do this, If am not wrong simple Group by with Max aggregate should work for you
select
ID_Number,
Date_01=max(Date_01),
Date_02=max(Date_02),
Date_03=max(Date_03),
Date_04=max(Date_04),
Date_05=max(Date_05)
from yourtable
group by ID_Number
max date per column for each ID
Grouping by ID_Number :
SELECT ID_Number AS Expr1, MAX(Date_01) AS Date_01, MAX(Date_02) AS Date_02, MAX(Date_03) AS Date_03, MAX(Date_04) AS Date_04, MAX(Date_05) AS Date_05
FROM ta1
GROUP BY ID_Number

Resources