Converting row to columns in SQL Server - sql

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

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

querying SQL Server 2005

I have a table that is time and milemarkers:
08:00 101.2
08:45 109.8
09:15 109.8
09:30 111.0
10:00 114.6
I need output that looks like this:
08:00-08:45 101.1-109.8
08:45-09:15 109.8-109.8
09:15-09:30 109.8-111.0
09:30-10:00 111.0-114.6
I figure I need 2 identical recordsets and somehow tie the first record of one to the second record of the other, but am clueless on how to accomplish that (or how to ask the question). Any help would be greatly appreciated.
Thanks in advance,
Ginny
The following query will get the next values:
select tm.*,
(select top 1 time
from timemilemarkers tm2
where tm2.time > tm.time
order by 1 desc
) as nexttime,
(select top 1 milemarker
from timemilemarkers tm2
where tm2.time > tm.time
order by 1 desc
) as nextmilemarker
from timemilemarkers tm;
You can put them into the form you want with something like:
select concat_ws('-', milemarker, nextmilemarker), concat_ws('-', time, nexttime)
from (select tm.*,
(select top 1 time
from timemilemarkers tm2
where tm2.time > tm.time
order by 1 desc
) as nexttime,
(select top 1 milemarker
from timemilemarkers tm2
where tm2.time > tm.time
order by 1 desc
) as nextmilemarker
from timemilemarkers tm
) tm
where nextmilemarker is not null;
Other way to do it is:
SQLFiddle
select cast(A.TIME_COL as varchar) + ' - ' + cast(B.TIME_COL as varchar),
cast(A.MILES as varchar) + ' - ' + cast(B.MILES as varchar)
from (select row_number() OVER (order by time_col) ID, * from TABLE_A) A
inner join (select row_number() OVER (order by time_col) ID, * from TABLE_A) B
on A.ID = B.ID - 1
UPDATE: this query will only works for SQL Server 2008 and upwards and obviously not answer your question. I will not erase the answer cause it can be helpful for othe people.
UPDATE2: It works on SQL Server 2005.
try this,
Declare #t table (times time(0), milemarkers decimal(5,2))
insert into #t
select '08:00','101.2' union all
select'08:45','109.8' union all
select'09:15','109.8' union all
select'09:30','111.0' union all
select'10:00','114.6'
;With cte1 as
(select *,ROW_NUMBER()over(order by times)rn from #t
)
,cte2 as
(select max(rn) rn1 from cte1)
, cte as
(select
(select times from cte1 where rn=1)lowerlimit,(select times from cte1 where rn=2)upperlimit,
(select milemarkers from cte1 where rn=1)lowerlimit1,(select milemarkers from cte1 where rn=2)upperlimit1
,1 rn from cte1
union all
select upperlimit,(select times from cte1 where rn=a.rn+2)
,upperlimit1,(select milemarkers from cte1 where rn=a.rn+2)
,rn+1
from cte a where a.rn<(select rn1 from cte2)
)
select distinct cast(lowerlimit as varchar(10))+'-'+cast(upperlimit as varchar(10)) ,
cast(lowerlimit1 as varchar(10))+'-'+cast(upperlimit1 as varchar(10))
from cte a where a.rn<(select rn1 from cte2)
Using CTE we can get the OutPut it is also other way to do Find below query
DECLARE #TABLE_A table(time_col time, miles float)
insert into #TABLE_A values ('08:00',101.2)
insert into #TABLE_A values ('08:45',109.8)
insert into #TABLE_A values ('09:15',109.8)
insert into #TABLE_A values ('09:30',111.0)
insert into #TABLE_A values ('10:00',114.6)
;WITH CTE AS
(
SELECT t.time_col,t.miles,t.RN FROM
(
Select ROW_NUMBER()OVER(ORDER BY time_col )RN,* FRom #TABLE_A
)t
INNER JOIN (
Select ROW_NUMBER()OVER(ORDER BY time_col )RN,* FRom #TABLE_A
)tt
ON t.RN = tt.RN
)
,CTE2(TimeSpan,Miles) AS
(
Select CONVERT(VARCHAR,c.time_col,108) +'-'+
(Select CONVERT(VARCHAR,time_col,108) FROM CTE WHERE RN = cc.RN + 1) As TimeSpan,
CAST(c.miles AS VARCHAR) +' - '+ (Select CAST(miles AS VARCHAR) FROM CTE WHERE RN = CC.RN + 1)AS Miles FROM CTE c
INNER JOIN CTE CC
ON CC.miles = c.miles
AND CC.time_col = c.time_col
)
Select TimeSpan,Miles from CTE2
WHERE TimeSpan IS NOT NULL

SQL- pad results with extra rows

I have a group of records that have a "Store" column. I need to basically split the result sets into groups of 13 records, creating blank rows to pad out each store to have 13 rows.
For simplicity, lets say I need groups of 4 records.
Example, given the below table:
-----------------
Store Name
-----------------
A John
A Bill
B Sam
C James
C Tim
C Chris
D Simon
D Phil
I need the results to look like:
-----------------
Store Name
-----------------
A John
A Bill
A
B Sam
B
B
C James
C Tim
C Chris
D Simon
D Phil
D
Is this at all possible with pure SQL? There are never going to be more than 3 rows for each store.
SQL Fiddle
Try this one -
DDL:
SET STATISTICS IO ON;
IF OBJECT_ID (N'tempdb.dbo.#temp') IS NOT NULL
DROP TABLE #temp
CREATE TABLE #temp
(
Store CHAR(1)
, Name VARCHAR(10)
)
INSERT INTO #temp (Store, Name)
VALUES
('A', 'John'), ('A', 'Bill'),
('B', 'Sam'), ('C', 'James'),
('C', 'Tim'), ('C', 'Chris'),
('D', 'Simon'), ('D', 'Phil')
Queries:
DevArt #1:
;WITH cte AS
(
SELECT
Store
, Name
, rn = ROW_NUMBER() OVER (PARTITION BY Store ORDER BY (SELECT 1))
FROM #temp
)
SELECT t.Store, Name = ISNULL(t3.Name, '')
FROM (
SELECT DISTINCT Store
FROM cte
) t
CROSS JOIN (SELECT rn = 1 UNION ALL SELECT 2 UNION ALL SELECT 3) t2
LEFT JOIN cte t3 ON t2.rn = t3.rn AND t.Store = t3.Store
DevArt #2:
SELECT t2.Store, Name = ISNULL(t3.Name, '')
FROM (
SELECT *
FROM (
SELECT Store, r = COUNT(1)
FROM #temp
GROUP BY Store
) t
CROSS APPLY (
VALUES (r), (r+1), (r+2)
) t2 (x)
) t2
LEFT JOIN #temp t3 ON t2.Store = t3.Store AND t2.x = t2.r
WHERE t2.x < 4
Alexander Fedorenko:
;WITH cte AS
(
SELECT DISTINCT Store
FROM #temp
)
SELECT o.Store, o.name
FROM cte s
CROSS APPLY (
SELECT TOP 3 x.Store, x.name
FROM (
SELECT s2.Store, s2.name
FROM #temp s2
WHERE s.Store = s2.Store
UNION ALL
SELECT s.Store, ''
UNION ALL
SELECT s.Store, ''
) x
) o
ErikE:
SELECT Store, Name
FROM (
SELECT
x.Store
, x.Name
, s = ROW_NUMBER() OVER (PARTITION BY x.Store ORDER BY x.s)
FROM #temp t
CROSS APPLY (
VALUES
(Store, Name, 0),
(Store, '', 1),
(Store, '', 1)
) x (Store, Name, S)
) z
WHERE s <= 3
ORDER BY Store
AmitSingh:
SELECT t.Store, Name = COALESCE(
(
SELECT name
FROM (
SELECT
row1 = ROW_NUMBER() OVER (PARTITION BY Store ORDER BY Store)
, *
FROM #temp
) c
WHERE t.[row] = c.row1
AND t.Store = c.Store
)
, '')
FROM
(
SELECT
[Row] = ROW_NUMBER() OVER (PARTITION BY a.Store ORDER BY a.Store)
, a.Store
FROM (
SELECT Store
FROM #temp
GROUP BY Store
) a
, (
SELECT TOP 3 Store
FROM #temp
) b
) t
Andriy M #1:
;WITH ranked AS
(
SELECT
Store
, Name
, rnk = ROW_NUMBER() OVER (PARTITION BY Store ORDER BY 1/0)
FROM #temp
)
, pivoted AS
(
SELECT
Store
, [1] = ISNULL([1], '')
, [2] = ISNULL([2], '')
, [3] = ISNULL([3], '')
FROM ranked
PIVOT (
MAX(Name)
FOR rnk IN ([1], [2], [3])
) p
)
, unpivoted AS
(
SELECT
Store
, Name
FROM pivoted
UNPIVOT (
Name FOR rnk IN ([1], [2], [3])
) u
)
SELECT *
FROM unpivoted
Andriy M #2:
;WITH ranked AS
(
SELECT
Store
, Name
, rnk = ROW_NUMBER() OVER (PARTITION BY Store ORDER BY 1/0)
FROM #temp
)
, padded AS
(
SELECT
Store
, Name
FROM ranked
PIVOT (
MAX(Name)
FOR rnk IN ([1], [2], [3])
) p
CROSS APPLY (
VALUES
(ISNULL([1], '')),
(ISNULL([2], '')),
(ISNULL([3], ''))
) x (Name)
)
SELECT *
FROM padded
Output:
Store Name
----- ----------
A John
A Bill
A
B Sam
B
B
C James
C Tim
C Chris
D Simon
D Phil
D
Statistics:
Query Presenter Scans Logical Reads
------------------- ----- -------------
DevArt #1 3 41
DevArt #2 2 9
Alexander Fedorenko 4 5
ErikE 1 1
AmitSingh 22 25
Andriy M #1 1 1
Andriy M #2 1 1
Query cost:
Extended statistics:
Execution statistics:
Query plan (from dbForge Studio for MS SQL):
Select t.store_id,Coalesce((Select Name from (
Select row_Number() Over(Partition by store_id order by store_id) as row1, * from stores)c
where t.row=c.row1 and t.store_id=c.store_id),'') as cfgg
from
(Select row_Number() Over(Partition by a.store_id order by a.store_id) as row,
a.store_id from
(Select store_id from stores group by store_id) a ,(Select top 3 store_id from stores)b
) t
SQL Fiddle Demo
One more option with APPLY operator
;WITH cte AS
(
SELECT store_id
FROM stores
GROUP BY store_id
)
SELECT o.store_id, o.name
FROM cte s CROSS APPLY (
SELECT TOP 3 x.store_id, x.name
FROM (
SELECT s2.store_id, s2.name
FROM stores s2
WHERE s.store_id = s2.store_id
UNION ALL
SELECT s.store_id, ''
UNION ALL
SELECT s.store_id, ''
) x
) o
Demo on SQLFiddle
Here's a query that works (SQL Server 2008 and up, can be fixed to work in 2005):
SELECT Store, Name
FROM (
SELECT
X.Store, X.Name, R = Row_Number() OVER (PARTITION BY X.Store ORDER BY X.S)
FROM
#temp T
CROSS APPLY (VALUES
(Store, Name, 0), (Store, '', 1), (Store, '', 1)
) X (Store, Name, S)
) Z
WHERE R <= 3
ORDER BY Store
;
According to SET STATISTICS IO ON;, here are performance statistics (all have negligible CPU at this low number of rows, perhaps more rows would help determine the best performer):
Query Presenter Scans Logical Reads
------------------- ----- -------------
ErikE 1 1
Alexander Fedorenko 4 5
Devart 3 41
AmitSingh 22 25
My query does not preserve the "original" ordering of the names for each store, however that is not a flaw because there is no concept of ordering in a relational database table. You must supply a column to order by if you want to preserve a particular sequence.
Yet another option, this time using PIVOT and UNPIVOT:
WITH ranked AS (
SELECT
store_id,
name,
rnk = ROW_NUMBER() OVER (PARTITION BY store_id ORDER BY 1/0)
FROM stores
),
pivoted AS (
SELECT
store_id,
[1] = ISNULL([1], ''),
[2] = ISNULL([2], ''),
[3] = ISNULL([3], '')
FROM ranked
PIVOT (
MAX(name) FOR rnk IN ([1], [2], [3])
) p
),
unpivoted AS (
SELECT
store_id,
name
FROM pivoted
UNPIVOT (
name FOR rnk IN ([1], [2], [3])
) u
)
SELECT *
FROM unpivoted
;
A SQL Fiddle demo to play with: http://sqlfiddle.com/#!3/354df/39.
Note that the UNPIVOT step in the above query has to be done in a separate SELECT from the PIVOT action. That is because UNPIVOT does not generate rows where columns listed in the IN column list contain NULLs. However, you could replace UNPIVOT with an equivalent technique (like CROSS APPLY) and thus move the unpivoting to the same subquery that does the pivoting:
WITH ranked AS (
SELECT
store_id,
name,
rnk = ROW_NUMBER() OVER (PARTITION BY store_id ORDER BY 1/0)
FROM stores
),
padded AS (
SELECT
store_id,
name
FROM ranked
PIVOT (
MAX(name) FOR rnk IN ([1], [2], [3])
) p
CROSS APPLY (
VALUES
(ISNULL([1], '')),
(ISNULL([2], '')),
(ISNULL([3], ''))
) x (name)
)
SELECT *
FROM padded
;
A SQL Fiddle demo for the modified version: http://sqlfiddle.com/#!3/354df/40.

is there an easier way than doing UNION ALL?

I have a rather large query which select data from a certain date range.
I would like to group data based on year.
Right now I have:
;with mappingTable as
(
select b.CLIENT_ID,f.patient_id,f.received_date,f.SPECIMEN_ID
from F_ACCESSION_DAILY f
join
(
select f.client_id,a.patient_id
from
(
SELECT
max(received_date) AS received_date
, patient_id AS Patient_ID
FROM F_ACCESSION_DAILY
group by PATIENT_ID
) a
join F_ACCESSION_DAILY f
on f.PATIENT_ID=a.Patient_ID
and f.RECEIVED_DATE=a.received_date
) b
on b.Patient_ID=f.PATIENT_ID
where f.RECEIVED_DATE between '20100101' and '20110101' - as you can see this data is only for 2010
) ---there's much more to this query
as you can see this data is only for 2010
but i would like to do union all for all years: 2008, 2009, 2010, 2011, 2012...
how do i do this without rewriting the query 5 times and doing a union all between all of them?
here's the entire monster query:
;with mappingTable as
(
select b.CLIENT_ID,f.patient_id,f.received_date,f.SPECIMEN_ID
from F_ACCESSION_DAILY f
join
(
select f.client_id,a.patient_id
from
(
SELECT
max(received_date) AS received_date
, patient_id AS Patient_ID
FROM F_ACCESSION_DAILY
group by PATIENT_ID
) a
join F_ACCESSION_DAILY f
on f.PATIENT_ID=a.Patient_ID
and f.RECEIVED_DATE=a.received_date
) b
on b.Patient_ID=f.PATIENT_ID
where f.RECEIVED_DATE between '20100101' and '20110101'
)
,
counted as(
SELECT
PATIENT_ID,
client_id,
--case when COUNT(*)>=12 then 12 else COUNT(*) end TimesTested,
COUNT(*) as timestested,
case when count(*)>1 then
(datediff(day,MIN(received_date),max(received_date)))
/(COUNT(*)-1)
else
0
end as testfreq
FROM mappingTable
GROUP BY
client_id,
patient_id
),counted2 as (
SELECT
client_id,
TimesTested,
CAST(COUNT(*) AS varchar(30)) AS count,
CAST(AVG(testfreq) as varchar(30)) as TestFreq,
CAST(STDEV(TestFreq) as varchar(30)) Stdv
FROM counted
GROUP BY
client_id,
TimesTested
),
counted3 as
(
SELECT
patient_id,
client_id,
TimesTested,
CAST(COUNT(*) AS varchar(30)) AS count,
AVG(testfreq) as TestFreq
FROM counted
GROUP BY
client_id,
TimesTested,
PATIENT_ID
)
,
CountOver12 as
( select client_id,count(*) count
from counted
where timestested>12
group by CLIENT_ID)
,
TotalAvgTestFreq as (
select client_id, SUM(testfreq) / count(testfreq) TotalAvgTestFreq
from counted3
group by client_id
)
,
unpivoted AS (
SELECT
client_id,
ColumnName + CAST(TimesTested AS varchar(10)) AS ColumnName,
ColumnValue
FROM counted2
UNPIVOT (
ColumnValue FOR ColumnName IN (count, TestFreq,stdv)
) u
),
pivoted AS (
SELECT
client_id clientid,
count1, TestFreq1,stdv1,
count2, TestFreq2,stdv2,
count3, TestFreq3,stdv3,
count4, TestFreq4,stdv4,
count5, TestFreq5,stdv5,
count6, TestFreq6,stdv6,
count7, TestFreq7,stdv7,
count8, TestFreq8,stdv8,
count9, TestFreq9,stdv9,
count10, TestFreq10,stdv10,
count11, TestFreq11,stdv11,
count12, TestFreq12,stdv12
FROM unpivoted
PIVOT (
MAX(ColumnValue) FOR ColumnName IN (
count1,TestFreq1,stdv1,
count2,TestFreq2,stdv2,
count3,TestFreq3,stdv3,
count4,TestFreq4,stdv4,
count5,TestFreq5,stdv5,
count6,TestFreq6,stdv6,
count7,TestFreq7,stdv7,
count8, TestFreq8, stdv8,
count9, TestFreq9, stdv9,
count10, TestFreq10,stdv10,
count11, TestFreq11,stdv11,
count12, TestFreq12,stdv12
)
) p
)
,
PatientStats as
(
select
distinct
f.client_id
,datediff(MM,c.mlis_date_established,GETDATE()) MonthsCustomer
,count(distinct patient_id) TotalPatients
,count(distinct specimen_id) TotalSpecimens
from mappingTable f
left join D_CLIENT c
on f.CLIENT_ID=c.CLIENT_ID
group by f.client_id,c.mlis_date_established
)
,
Over12
as
(
select client_id,SUM(c) sumcount from
(
select CLIENT_ID,COUNT(*) c
from mappingTable
group by CLIENT_ID,PATIENT_ID
having count(*)>12
) a
group by client_id
),
GetMedian as(
select client_id, avg(timestested) median_testfreq
from
(
select client_id,
timestested,
rn=row_number() over (partition by CLIENT_ID
order by timestested),
c=count(timestested) over (partition by CLIENT_ID)
from counted3
where timestested>1
) g
where rn in (round(c/2,0),c/2+1)
group by client_id
)
, final as (
SELECT p.*,pivoted.*,c12.count [Count13+],Over12.sumcount SumofGreaterThan12,t.TotalAvgTestFreq,median.median_testfreq
FROM pivoted
left join PatientStats p
on p.CLIENT_ID=pivoted.CLIENTID
left join Over12
on over12.CLIENT_ID=p.CLIENT_ID
left join TotalAvgTestFreq t
on t.CLIENT_ID=p.CLIENT_ID
left join CountOver12 C12
on c12.CLIENT_ID=p.CLIENT_ID
left join GetMedian median
on median.CLIENT_ID=p.CLIENT_ID
where p.CLIENT_ID not in (select CLIENTid from SalesDWH..TestPractices)
)
/* Get the data into a temp table */
SELECT * INTO #TempTable
FROM final
/* Drop the cloumns that are not needed */
ALTER TABLE #TempTable
DROP COLUMN clientid
/* Get results and drop temp table */
SELECT * FROM #TempTable
DROP TABLE #TempTable
Create a table function:
CREATE FUNCTION fn_get_data_by_date_range
(
#start AS VARCHAR(8),
#end AS VARCHAR(8)
)
RETURNS TABLE
AS
RETURN
(
...your query...
WHERE f.RECEIVED_DATE BETWEEN #start AND #end
)
then you can UNION different call of that function:
SELECT * FROM fn_get_data_by_date_range('20100101','20110101')
UNION ALL
SELECT * FROM fn_get_data_by_date_range('20090101','20100101')
UNION ALL
....
UNION ALL
SELECT * FROM fn_get_data_by_date_range('20070101','20080101')

Select In PIVOT

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;