Select In PIVOT - sql

Is there any way to have a CASE SELECT Statement in a PIVOTED Column. My Code is as follows
SELECT PName, [RN], [HA], [LVN], [MSW], [SC]
FROM
(
Query
) src
pivot
(
max(Visits)
for Discipline in ([RN], [HA], [LVN], [MSW], [SC])
) piv
I am getting the output as follows
Pname RN HA LVN MSW SC
AA AG-2/W LO-1/W NA-1/W SK-2/W NO-2/MON
AA JL-2/W NULL NULL NULL NULL
Because there have been 2 RNs assigned to 1 PN I want to summarize the results only in 1 Row and select only 1 value to be displayed in the RN column so that the result is only as follows based on my condition.
Pname RN HA LVN MSW SC
AA JL-2/W LO-1/W NA-1/W SK-2/W NO-2/MON

Without seeing your full query, you should be able to apply a row_number to the inner query and then use a WHERE clause similar to this:
SELECT PName, [RN], [HA], [LVN], [MSW], [SC]
FROM
(
<yourQuery>, row_number() over(order by somefield) rn -- add a rownumber here
) src
pivot
(
max(Visits)
for Discipline in ([RN], [HA], [LVN], [MSW], [SC])
) piv
where rn = 1
If you post your full query, there might be other ways to do this.
edit, using your info from a previous question, your query would be like this:
select patname, [HA], [MSW], [RN]
from
(
select patName, Disc,
sname+' '+schedule new_value,
row_number() over(partition by patname, disc order by disc) rowNum
from yourquery
) src
pivot
(
max(new_value)
for disc in ([HA], [MSW], [RN])
) piv
where rownum = 1
See SQL Fiddle with Demo
Or you can use:
select *
from
(
SELECT PName, [RN], [HA], [LVN], [MSW], [SC] , row_number() over(partition by PName order by PName) rn
FROM
(
<yourQuery>
) src
pivot
(
max(Visits)
for Discipline in ([RN], [HA], [LVN], [MSW], [SC])
) piv
) x
where rn = 1

You'll have to remove the data AFTER the pivoting, because [RN] itself is subject to a MAX condition, i.e. it is itself a pivot column. Wrap it in a CTE, apply a RowNumber() function and partition correctly, then filter it for just 1 row per partition.
;WITH CTE AS (
SELECT PName, [RN], [HA], [LVN], [MSW], [SC],
ROW_NUMBER() OVER (partition by PName order by [RN] ASC) RowNum
FROM
(
Query
) src
pivot
(
max(Visits)
for Discipline in ([RN], [HA], [LVN], [MSW], [SC])
) piv
)
SELECT *
FROM CTE
WHERE RowNum = 1;

Related

Results of a CTE inside a subquery and row_number with a couple order by

I have a query that runs as follows:
WITH teste1 as (
SELECT
CONCAT(a.pid, a.num_ordenado) as id_despacho,
a.pid,
a.created_at,
a.nota,
a.from_id,
a.from_nome
FROM (
SELECT pid, id,
(ROW_NUMBER() over (partition by pid order by created_at)) as num_ordenado,
from_id, from_nome, nota, created_at
FROM mytable_a) as a
),
teste2 as (
SELECT
CONCAT(t.pid, t.ordenado) as id_despacho,
t.ordenado,
t.pid as id_doc,
t.data as diahora,
CONCAT
(
'Evento: ', t.evento
) as conteudo2,
'' as pasta,
t.from_id,
t.from_nome,
t.to_id,
t.to_nome
FROM
(
SELECT pid, data,
(ROW_NUMBER() over (partition by pid order by data)) as ordenado,
from_id, from_nome, to_id, to_nome, evento
FROM mytable_t) as t
)
SELECT *
FROM teste2 as t2
LEFT JOIN teste1 as t1
ON t2.id_despacho = t1.id_despacho
WHERE t2.conteudo2 <> 'Evento: Campo bloqueado' AND t2.conteudo2 <> 'Evento: Campo desbloqueado'
In each CTE, I order the ID's by datetime and then create a new ID structure on which I join by that new ID at the last query. I'm wondering how could I do to now order them again by datetime.
My questions then would be:
Can I use the results of a CTE (teste1 and teste2 tables) inside a subquery? Something like this (not working)
SELECT
t2.id_despacho,
t2.id_doc,
t2.diahora,
t2.conteudo2,
t1.id_despacho,
t1.created_at,
t1.nota,
(ROW_NUMBER() OVER (PARTITION BY id_doc ORDER BY diahora, created_at)) AS ordenado_final
FROM
(SELECT *
FROM teste2 AS t2
LEFT JOIN teste1 AS t1 ON t2.id_despacho = t1.id_despacho
WHERE t2.conteudo2 <> 'Evento: Campo bloqueado'
AND t2.conteudo2 <> 'Evento: Campo desbloqueado')
Does that ROW_NUMBER() work like that? Can I order by two different columns?
(ROW_NUMBER() OVER (PARTITION BY id_doc
ORDER BY diahora, created_at)) AS ordenado_final

Compare Column A of Row 1 with Column B of Row 2 in Same table

I have a table name 'Table A' where I need to get the all values based on two columns 'AdviserBusinessId' and 'ClientcontactGuid' having count > 1. I am able to achieve this using self join as below query.
select gc.AdviserBusinessId,gc.ClientContactGuid,gc.PlanStartDate,gc.PlanEndDate,gc.ClientEngagementGuid, gc.RenewalGuid,
ROW_NUMBER() over(partition by gc.adviserbusinessid,gc.clientcontactguid order by gc.planenddate asc) as rownum from GENIUS_ClientEngagement gc
inner join(
select AdviserBusinessId,ClientContactGuid from GENIUS_ClientEngagement
group by AdviserBusinessId,ClientContactGuid having count(*) > 1) B
on gc.AdviserBusinessId = b.AdviserBusinessId and gc.ClientContactGuid = b.ClientContactGuid
And this is what the table looks like:
[![enter image description here][1]][1]
Now my main point is that, I want to compare PlanEndDate of row 1 with PlanStartDate of row 2 and get the rows if PlanEndDate > PlanStartDate. Let's take an example of above two rows, if suppose the planstartdate was < planenddate then I just want to populate those above two rows.
Will cursor or loop be helpful in this ?
Thanks in advance. Any suggestions will be appreciated.
Use analytic functions:
SELECT AdviserBusinessId,
ClientContactGuid,
PlanStartDate,
PlanEndDate,
ClientEngagementGuid,
RenewalGuid,
rn
FROM (
SELECT AdviserBusinessId,
ClientContactGuid,
PlanStartDate,
PlanEndDate,
ClientEngagementGuid,
RenewalGuid,
ROW_NUMBER() OVER (
PARTITION BY adviserbusinessid, clientcontactguid
ORDER BY planEndDate asc
) AS rn,
COUNT(*) OVER (
partition by adviserbusinessid, clientcontactguid
) AS num_rows,
LEAD(planStartDate) OVER (
PARTITION BY adviserbusinessid, clientcontactguid
ORDER BY planEndDate asc
) AS next_start,
LAG(planEndDate) OVER (
PARTITION BY adviserbusinessid, clientcontactguid
ORDER BY planEndDate asc
) AS prev_end
FROM GENIUS_ClientEngagement
) gce
WHERE num_rows > 1
AND ( (rn = 1 AND planEndDate > next_start)
OR (rn = 2 AND prev_end > planStartDate) )
You can use self join to achieve this. Something like this:
SELECT * FROM TableA A
LEFT JOIN TableA B ON A.ClientContactGuid = B.ClientContactGuid AND (A.RowNum+1) = B.RowNum
WHERE A.PlanEndDate>B.PlanStartDate OR B.PlanStartDate IS NULL
This was what I wanted, thanks to #MTO for the direction.
with cte
as(
select gc.AdviserBusinessId,gc.ClientContactGuid,gc.PlanStartDate,gc.PlanEndDate,gc.ClientEngagementGuid, gc.RenewalGuid,
ROW_NUMBER() over(partition by gc.adviserbusinessid,gc.clientcontactguid order by planenddate desc) as rownum
from GENIUS_ClientEngagement gc
inner join(
select AdviserBusinessId,ClientContactGuid from GENIUS_ClientEngagement
group by AdviserBusinessId,ClientContactGuid having count(*) > 1
) B
on gc.AdviserBusinessId = b.AdviserBusinessId and gc.ClientContactGuid = b.ClientContactGuid
)
select *,ROW_NUMBER() over(partition by adviserbusinessid,clientcontactguid order by planenddate asc) as rn,
LEAD(PlanStartDate) OVER (
PARTITION BY adviserbusinessid, clientcontactguid
ORDER BY planEndDate asc
) AS next_start,
LAG(planEndDate) OVER (
PARTITION BY adviserbusinessid, clientcontactguid
ORDER BY planEndDate asc
) AS prev_ends into #temp2 from cte
where rownum <=2
select AdviserBusinessId,ClientContactGuid,PlanStartDate,PlanEndDate,ClientEngagementGuid,RenewalGuid from #temp2 where
( (rn = 1 AND planEndDate > next_start)
OR (rn = 2 AND prev_ends > planStartDate) )
drop table #temp2

ORA-00933: SQL command not properly ended on Table Alias

Having issues getting this to work. Each query works individually however when I try to alias each Subquery to work the Join I get the error:
SQL Command not properly ended. Any suggestions would be extremely appreciated.
Select C.*
From
(
(
Select
a.*,
Row_Number() Over(Partition By referral_id Order By start_date,line) as rn
from hcclsc.referral_Bed_Day a
) A
Inner Join (
Select
a.referral_id,
max(rn) as vn
From (
Select
referral_id,
line,
bed_day_type_id,
start_date,
end_date,
Row_Number() Over(Partition by referral_id Order By start_date, line) as rn
From HCCLSC.referral_Bed_Day
) a
Group by referral_id
) B
On A.referral_ID = B.referral_id and a.rn = b.vn
) C
You're joining A to B, but then not selecting a anything from those joined subqueries.
This part:
Select C.*
From
(
(
would need to specify columns to select from the join; if you want all of them from both subqueries then:
Select C.*
From
(
Select *
From
(
but then that extra level of subquery isn't really adding anything, and you can remove the C level:
Select *
From
(
Select
a.*,
Row_Number() Over(Partition By referral_id Order By start_date,line) as rn
from hcclsc.referral_Bed_Day a
) A
Inner Join (
Select
a.referral_id,
max(rn) as vn
From (
Select
referral_id,
line,
bed_day_type_id,
start_date,
end_date,
Row_Number() Over(Partition by referral_id Order By start_date, line) as rn
From HCCLSC.referral_Bed_Day
) a
Group by referral_id
) B
On A.referral_ID = B.referral_id and a.rn = b.vn
try like below by using cte
with cte as
(
Select
a.referral_id
max(rn) as vn
From
(Select
referral_id
,line
,bed_day_type_id
,start_date
,end_date
,Row_Number() Over(Partition by referral_id Order By start_date, line) as rn
From
HCCLSC.referral_Bed_Day
) a Group by referral_id
), cte2 as
(
Select
a.*
,Row_Number() Over(Partition By referral_id Order By start_date,line) as rn
from
hcclsc.referral_Bed_Day a
) select A.*,B.* from cte A join cte2 B
on A.referral_ID = B.referral_id and A.vn= B.rn

How do I JOIN another table to this code in SQL?

I need to JOIN a table named IB to the code below. I need to pull in the following fields from IB: QOO, QOH, QCM and AVG. The JOIN conditions are IJ.IJITEM = IB.IBITEM and IJ.IJLOC = IB.IBLOC
;WITH cte AS
(
SELECT IJLOC, IJITEM, IJDATE, IJLCGT,
rn = ROW_NUMBER() OVER (PARTITION BY IJITEM, IJLOC ORDER BY IJDATE DESC)
FROM dbo.IJ
)
SELECT IJLOC, IJITEM, IJDATE, IJLCGT
FROM cte WHERE rn = 1;
One method, which allows for a little more complexity than just JOINing the IB table to "cte" in your final SELECT is to nest another CTE using the current one as the table. For example:
;WITH cte AS
(
SELECT IJLOC, IJITEM, IJDATE, IJLCGT,
rn = ROW_NUMBER() OVER (PARTITION BY IJITEM, IJLOC ORDER BY IJDATE DESC)
FROM dbo.IJ
),
filtered AS (
SELECT IJLOC, IJITEM, IJDATE, IJLCGT
FROM cte
WHERE rn = 1
)
SELECT ib.QOO, ib.QOH, ib.QCM, ib.[AVG]
FROM ib
INNER JOIN filtered
ON filtered.IJITEM = IB.IBITEM
AND filtered.IJLOC = IB.IBLOC
Another option, depending on how the query optimizer handles the JOINs between all the tables, and if you don't need to return any of the fields from the IJ table, is to insert the results of your CTE into a temp table and then JOIN to that. For example:
CREATE TABLE #Temp (IJITEM DataType, IJLOC DataType)
;WITH cte AS
(
SELECT IJLOC, IJITEM, IJDATE, IJLCGT,
rn = ROW_NUMBER() OVER (PARTITION BY IJITEM, IJLOC ORDER BY IJDATE DESC)
FROM dbo.IJ
)
INSERT INTO #Temp (IJITEM, IJLOC)
SELECT IJITEM, IJLOC
FROM cte
WHERE rn = 1;
SELECT ib.QOO, ib.QOH, ib.QCM, ib.[AVG]
FROM ib
INNER JOIN #Temp tmp
ON tmp.IJITEM = IB.IBITEM
AND tmp.IJLOC = IB.IBLOC
;
WITH cte
AS ( SELECT IJLOC ,
IJITEM ,
IJDATE ,
IJLCGT ,
rn = ROW_NUMBER() OVER ( PARTITION BY IJITEM, IJLOC ORDER BY IJDATE DESC )
FROM dbo.IJ
)
SELECT IJLOC ,
IJITEM ,
IJDATE ,
IJLCGT ,
IB.QOO ,
IB.QOH ,
IB.QCM ,
IB.[AVG]
FROM cte
INNER JOIN IB ON cte.IJITEM = IB.IBITEM
AND cte.IJLOC = IB.IBLOC
WHERE cte.rn = 1 ;

Converting row to columns in SQL Server

I have a query that returns the following result set:
patName SName DISC SCHEDULE
JM AA HA 2 per Week
JM MAC MSW 1 per Month
JM ANG RN 1 per Week
JM JON RN 1 per Week
JM LRH RN 1 per Week
Is there any way I could display the result as follows using PIVOT
PATNAME HA MSW RN
JM AA 2/Week MAC 1/Month ANG 1/week
JON 1/Week
LRH 1/Week
Edit, my query is as follows:
SELECT PatientName, [RN], [HA], [LVN], [MSW], [SC]
FROM
(
SELECT DISTINCT (tblPatient.FirstName +' '+ tblPatient.LastName) As PatientName,
(tblStaff.StaffFirstName+' '+tblStaff.StaffLastName) As StaffName,
(tblStaffDiscipline.Discipline)As Discipline,
CAST(tblFrequencyOfVisit.NoOfVisit As Varchar)+' per '
+ REPLACE (tblFrequencyOfVisit.Period,'/','') AS Visits new_value,
row_number() over(partition by PatientName, Discipline order by Discipline) rowNum
FROM tblPatient INNER JOIN
tblFrequencyOfVisit
ON tblPatient.PatientId = tblFrequencyOfVisit.PatientId
INNER JOIN tblStaffAssignment
ON tblPatient.PatientId = tblStaffAssignment.PatientId
AND tblFrequencyOfVisit.PatientId = tblStaffAssignment.PatientId
INNER JOIN tblStaffDiscipline
ON tblFrequencyOfVisit.DisciplineId = tblStaffDiscipline.DisciplineId
INNER JOIN tblStaff
ON tblStaffAssignment.StaffId = tblStaff.StaffId
AND tblStaffDiscipline.Discipline = tblStaff.StaffDisciplane
)src
pivot
(
max(new_value)
for Discipline in ([RN], [HA], [LVN], [MSW], [SC])
) piv
WHERE
tblpatient.PatientId = '138'
AND NOT tblPatient.SOC IS NULL
AND tblPatient.EOC IS NULL
AND tblPatient.Hospiceid = '1'
AND tblFrequencyofVisit.FromDate =
(Select MAX(FROMDATE)
From tblfrequencyofVisit
Where tblFrequencyOfVisit.PatientId = tblPatient.PatientId
AND tblFrequencyofVisit.Disciplineid = tblStaffDiscipline.Disciplineid )
You can use the PIVOT function to perform this. If you have known values, then you can hard-code the columns using a static pivot. To get the grouping correct in the PIVOT, I included a row_number() so the result will include each record not just the max() value per patname:
select patname, [HA], [MSW], [RN]
from
(
select patName, Disc,
sname+' '+schedule new_value,
row_number() over(partition by patname, disc order by disc) rowNum
from <yourquery here>
) src
pivot
(
max(new_value)
for disc in ([HA], [MSW], [RN])
) piv
See SQL Fiddle with Demo
If you have unknown values in the DISC field, then you can use dynamic SQL to pivot the data:
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT distinct ',' + QUOTENAME(disc)
from yourquery
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT patname, ' + #cols + '
from
(
select patName, Disc,
sname+'' ''+schedule new_value,
row_number() over(partition by patname, disc order by disc) rowNum
from <yourquery here>
) x
pivot
(
max(new_value)
for Disc in (' + #cols + ')
) p '
exec(#query)
See SQL Fiddle with Demo
If you do not have a PIVOT function available, then this can be replicated using an aggregate function and a CASE statement:
select patname,
max(case when disc='HA' then new_value end) HA,
max(case when disc='MSW' then new_value end) MSW,
max(case when disc='RN' then new_value end) RN,
rowNum
from
(
select patName, Disc,
sname+' '+schedule new_value,
row_number() over(partition by patname, disc order by disc) rowNum
from yourquery
) src
group by patname, rownum
See SQL Fiddle with Demo
Edit, based on your query that you posted it looks like you might need to use something like this:
SELECT PatientName, [RN], [HA], [LVN], [MSW], [SC]
FROM
(
SELECT
(tblPatient.FirstName +' '+ tblPatient.LastName) As PatientName,
(tblStaff.StaffFirstName+' '+tblStaff.StaffLastName) As StaffName,
(tblStaffDiscipline.Discipline)As Discipline,
CAST(tblFrequencyOfVisit.NoOfVisit As Varchar)+' per '+ REPLACE (tblFrequencyOfVisit.Period,'/','') AS Visits new_value,
row_number() over(partition by PatientName, Discipline order by Discipline) rowNum
FROM tblPatient
INNER JOIN tblFrequencyOfVisit
ON tblPatient.PatientId = tblFrequencyOfVisit.PatientId
INNER JOIN tblStaffAssignment
ON tblPatient.PatientId = tblStaffAssignment.PatientId
AND tblFrequencyOfVisit.PatientId = tblStaffAssignment.PatientId
INNER JOIN tblStaffDiscipline
ON tblFrequencyOfVisit.DisciplineId = tblStaffDiscipline.DisciplineId
INNER JOIN tblStaff
ON tblStaffAssignment.StaffId = tblStaff.StaffId
AND tblStaffDiscipline.Discipline = tblStaff.StaffDisciplane
WHERE tblpatient.PatientId = '138'
AND NOT tblPatient.SOC IS NULL
AND tblPatient.EOC IS NULL
AND tblPatient.Hospiceid = '1'
AND tblFrequencyofVisit.FromDate = (Select MAX(FROMDATE)
From tblfrequencyofVisit
Where tblFrequencyOfVisit.PatientId = tblPatient.PatientId
AND tblFrequencyofVisit.Disciplineid = tblStaffDiscipline.Disciplineid )
)src
pivot
(
max(new_value)
for Discipline in ([RN], [HA], [LVN], [MSW], [SC])
) piv