is there an easier way than doing UNION ALL? - sql

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')

Related

How to retrieve Count of all records and other records in single query

I have the following query
select name,trip_id from main order by name
I want to retrieve count of all the records and all the columns in the tables.
for ex if i have 200 rows in table i want to have the output as
select name,trip_id,count(*) from main
Is it possible in a single query?
Use analytic count:
select name, trip_id,
count(*) over() as cnt
from main
order by name
;
DECLARE
#Main TABLE
(
[name] VARCHAR(50),
trip_id INT
);
INSERT INTO #Main
(
[name],
trip_id
)
VALUES
(
'Jim', 1
),
(
'Ian', 2
),
(
'Susan', 2
);
-- Option 1
SELECT
[name],
trip_id,
COUNT(*) OVER () AS ct
FROM
#Main;
-- Option 2
SELECT
[name],
trip_id,
(
SELECT
COUNT(*)
FROM
#Main
)
ct
FROM
#Main;
-- Option 3
SELECT
[name],
trip_id,
v.ct
FROM
#Main
CROSS APPLY
(
SELECT
COUNT(*) FROM #Main
) v (ct);
-- Option 4
SELECT
t1.[name],
t1.trip_id,
t2.ct
FROM
#Main t1
JOIN
(
SELECT
COUNT(*) ct
FROM
#Main
) t2
ON 1 = 1;
-- Option 5
SELECT
t1.[name],
t1.trip_id,
t2.ct
FROM
#Main t1
CROSS JOIN
(
SELECT
COUNT(*) ct
FROM
#Main
) t2;

How to use CTE recursion to get a running total of a column

I have been researching CTE recursion, but I still seem to be confused.
I have table: utb(date, b_id, v_id, b_vol)
I need to get the running total of the column: b_vol.
The catch is that I need to divide if the row_number is even, and multiply if it is odd, so essentially:
P1= b_vol1, P2 = b_vol1/b_vol2, P3= b_vol1/b_vol2*b_vol3,
P4= b_vol1/b_vol2*b_vol3/b_vol4
So, it is basically P(n)= (P(n-1)(*OR/(b_vol(n))
I can't seem to figure out how to put that into a query.
Thanks for taking the time to read this. I hope you can help.
My sample table only has 1 column B_VOL. Try this
DECLARE #SampleData AS TABLE ( B_VOL int)
INSERT INTO #SampleData VALUES (50), (50), ( 50), (50) ,(155), (255)
;WITH temp AS
(
SELECT sd.*, row_number() OVER(ORDER BY (SELECT null)) - 1 AS RowIndex FROM #SampleData sd
)
,cte AS
(
SELECT TOP 1 t.RowIndex, CAST( t.B_VOL AS decimal(18,7)) AS sv FROM temp t ORDER BY t.RowIndex ASC
UNION ALL
SELECT t.RowIndex, CAST(cte.sv * (CASE WHEN t.RowIndex % 2 = 1 THEN CAST(1 AS decimal(18,7))/t.B_VOL ELSE t.B_VOL END) AS decimal(18,7)) AS sv
FROM cte
INNER JOIN temp t ON cte.RowIndex + 1 = t.RowIndex
)
SELECT t.*, c.sv
FROM temp t
INNER JOIN cte c ON t.RowIndex = c.RowIndex
OPTION(MAXRECURSION 0)
First, a CTE is not the best way to solve this problem. But . . .
with u as (
select u.*, row_number() over (order by date) - 1 as seqnum
from utb u
),
cte as (
select seqnum, b_vol as result
from u
union all
select cte.seqnum, cte.result * (case when seqnum % 2 = 1 then 1.0 / b_vol else b_vol end) as result
from cte join
u
on u.seqnum = cte.seqnum + 1
)
select *
from cte;
you should try this,
DECLARE #SampleData AS TABLE ( B_VOL int)
INSERT INTO #SampleData VALUES (50), (50), ( 50), (50) ,(155), (255)
;with CTE as
(
select S.B_VOL,ROW_NUMBER()over(order by ((select null)))rn
from #SampleData S
)
,CTE1 AS
(
select b_vol,cast(b_vol as float) sv,1 rn1
from cte where rn=1
union ALL
select c.b_vol,
case when (c1.rn1+1)%2=0
THEN c1.sv/cast(c.b_vol as float)
ELSE
c1.sv*cast(c.b_vol as float)
end
,c1.rn1+1
from CTE C
inner join CTE1 c1
on c.rn=c1.rn1+1
where c1.rn1<7
)
select * from cte1

How to cast to varchar and add % sign to SQL

Ive been pulling my hair out to get around this..how can i convert this to a varchar and add the % symbol to the results?
I have placed the code below of the query and have tried to cast it but keep getting errors that i don't know how to fix. Can someone pleae make some suggestions on how to either simplify and prevent divide by zero issues also.
select 'Conversion Rate' as Type,
(
SELECT
(
COALESCE
(
CAST(CAST(nullif(t.ConvertedTrials,0) AS NUMERIC(18,2)) / (CAST(nullif(t.UnconvertedTrials,0) AS NUMERIC(18,2))) * 100 as decimal(10,2))
,
0
)
) AS Percentage
FROM (
SELECT
UnconvertedTrials = (
SELECT count(*) FROM
(
select memberid from membership where discountcodeid = '79a7fd7c-9ebe-4ec0-8ac0-95ea274f1f64' Group by membership.memberid
) as a
),
ConvertedTrials = (
SELECT count(*) FROM
(
SELECT membership.memberid
FROM Membership, Package
WHERE membership.PackageId = Package.Id
AND Package.PackageTypeId != 1
AND membership.memberid in (select memberid from membership where discountcodeid = '79a7fd7c-9ebe-4ec0-8ac0-95ea274f1f64')
Group by membership.memberid
) as b
)
) as t
) as Total
select 'Conversion Rate' as Type,
RTRIM(CAST((
SELECT
(
COALESCE
(
CAST(CAST(nullif(t.ConvertedTrials,0) AS NUMERIC(18,2)) / (CAST(nullif(t.UnconvertedTrials,0) AS NUMERIC(18,2))) * 100 as decimal(10,2))
,
0
)
) AS Percentage
FROM (
SELECT
UnconvertedTrials = (
SELECT count(*) FROM
(
select memberid from membership where discountcodeid = '79a7fd7c-9ebe-4ec0-8ac0-95ea274f1f64' Group by membership.memberid
) as a
),
ConvertedTrials = (
SELECT count(*) FROM
(
SELECT membership.memberid
FROM Membership, Package
WHERE membership.PackageId = Package.Id
AND Package.PackageTypeId != 1
AND membership.memberid in (select memberid from membership where discountcodeid = '79a7fd7c-9ebe-4ec0-8ac0-95ea274f1f64')
Group by membership.memberid
) as b
)
) as t
) AS NVARCHAR(50))) + '%' as Total
your actual percentage is quite a large sub-query, it's hard to see how to enclose it in brackets - I had about 10 goes - is it any good yet?
maybe it's easier to wrap the whole query in another select e.g
SELECT A,B FROM (<your query>) AS AQUERY
(which should give exactly same results as your query) - THEN work on formatting B in the outer query
Here is my second way of doing it
SELECT ORIGINAL.Type, RTRIM(CAST(ORIGINAL.Total as varchar(80))) + '%' AS Total
FROM
(
select 'Conversion Rate' as Type,
(
SELECT
(
COALESCE
(
CAST(CAST(nullif(t.ConvertedTrials,0) AS NUMERIC(18,2)) / (CAST(nullif(t.UnconvertedTrials,0) AS NUMERIC(18,2))) * 100 as decimal(10,2))
,
0
)
) AS Percentage
FROM (
SELECT
UnconvertedTrials = (
SELECT count(*) FROM
(
select memberid from membership where discountcodeid = '79a7fd7c-9ebe-4ec0-8ac0-95ea274f1f64' Group by membership.memberid
) as a
),
ConvertedTrials = (
SELECT count(*) FROM
(
SELECT membership.memberid
FROM Membership, Package
WHERE membership.PackageId = Package.Id
AND Package.PackageTypeId != 1
AND membership.memberid in (select memberid from membership where discountcodeid = '79a7fd7c-9ebe-4ec0-8ac0-95ea274f1f64')
Group by membership.memberid
) as b
)
) as t
) as Total
) ORIGINAL

expecting output with out using left join

first table is my input and expecting output like second table with out using left join.
this is the table data
declare #table table
(customer_id int,
indicator bit,
salary numeric(22,6)
,netresult numeric(22,6))
INSERT INTO #table (
customer_id
,indicator
,salary
)
VALUES
(1,1,2000),
(1,1,3000),
(2,1,1000),
(1,0,500),
(1,1,5000),
(2,1,2000),
(2,0,100)
select * from #table order by customer_id,indicator desc
I tried in below method it works. Is there any better alternative?
SELECT a.customer_id
,a.indicator
,a.salary
,netresult=p_salary-(2*n_salary)
FROM (
SELECT customer_id
,indicator
,salary
,sum(salary) OVER (PARTITION BY customer_id) p_salary
FROM #table
) a
LEFT JOIN (
SELECT customer_id
,indicator
,salary
,sum(salary) OVER (PARTITION BY customer_id) n_salary
FROM #table
WHERE indicator = 0
) b ON a.customer_id = b.customer_id
order by customer_id,indicator desc
Expected Output
I think you want this:
select t.customer_id, t.indicator,
sum(case when indicator = 1 then salary else - salary end) over (partition by customer_id) as netresult
form #table t;
No joins are necessary.
with math
select t.customer_id, t.indicator, t.salary
, sum((( t.indicator * 2) -1) * salary) over (partition by customer_id) as netresult
from #table t;

Delete rows following a duplicate

I have a list of user login and logout stamps. Unfortunately a LOGIN entry might not always be followed by a LOGOUT entry.
I wish to delete any row which has the same [event] and [user_id] as previous row when ordered by [event_date]
Any suggestions on how to do this?
Example table
CREATE TABLE #LOG (
[id] int IDENTITY(1,1),
[user_id] int,
[event] varchar(50),
[event_date] datetime
);
INSERT INTO #LOG ([user_id], [event], [event_date])
SELECT 1,'LOGIN',{ts '2010-12-15 15:31:59'}
UNION ALL SELECT 1,'LOGOUT',{ts '2010-12-15 15:32:55'}
UNION ALL SELECT 1,'LOGIN',{ts '2010-12-15 15:38:04'}
UNION ALL SELECT 1,'LOGOUT',{ts '2010-12-15 15:38:17'}
UNION ALL SELECT 1,'LOGOUT',{ts '2010-12-15 15:38:45'} -- Delete
UNION ALL SELECT 2,'LOGIN',{ts '2010-12-15 16:59:39'}
UNION ALL SELECT 2,'LOGOUT',{ts '2010-12-15 17:00:08'}
UNION ALL SELECT 2,'LOGOUT',{ts '2010-12-15 17:00:39'} -- Delete
UNION ALL SELECT 2,'LOGOUT',{ts '2010-12-15 17:01:16'} -- Delete
UNION ALL SELECT 2,'LOGIN',{ts '2010-12-15 17:01:38'}
UNION ALL SELECT 2,'LOGIN',{ts '2010-12-15 17:02:26'} -- Delete
UNION ALL SELECT 2,'LOGOUT',{ts '2010-12-15 17:02:39'}
;WITH T1 AS
(
SELECT * ,
ROW_NUMBER() OVER (ORDER BY event_date)-
ROW_NUMBER() OVER (PARTITION BY [user_id], [event]
ORDER BY event_date) AS Grp
FROM #LOG
),T2 AS
(
SELECT
ROW_NUMBER() OVER (PARTITION BY [user_id], [event], Grp
ORDER BY event_date) RN
FROM T1
)
DELETE FROM T2
WHERE RN > 1
Using the ROW_NUMBER functionality of SQL Server would be an option
SQL Statement
;WITH q AS (
SELECT Rownumber = ROW_NUMBER() OVER (ORDER BY user_id, event_date)
, user_id
, event
, event_date
FROM #LOG
)
DELETE FROM #LOG
FROM #LOG l
INNER JOIN (
SELECT q2.*
FROM q q1
INNER JOIN q q2 ON q2.Rownumber = q1.Rownumber + 1
AND q2.user_id = q1.user_id
AND q2.event = q1.event
) q ON q.user_id = l.user_id
AND q.event_date = l.event_date
SELECT *
FROM #LOG
My understanding is that you want to delete entries such that the pattern is always In,Out,In,Out,etc.
This means a record is deleted if the preceding record (when order by user_id, then event_date), is of the same event.
There are two options I'd use to go about this...
DELETE
#log
WHERE
event = (
SELECT
TOP 1
event
FROM
#log AS [preceding]
WHERE
[preceding].user_id = #log.user_id
AND [preceding].event_date < #log.event_date
ORDER BY
[preceding].event_date DESC
)
Or...
WITH ordered_log AS (
SELECT
ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY event_date) AS user_event_id,
*
FROM
#log
)
DELETE
ordered_log
FROM
ordered_log
INNER JOIN
ordered_log AS [preceding]
ON [preceding].login_id = [ordered_log].login_id
AND [preceding].user_event_id = [ordered_log].user_event_id - 1
WHERE
[preceding].event = [ordered_log].event
Either way, I highly recommend an Index covering user_id then event_date.
Note: The first version does not cope with the possibility of two events having the same timestamp. The latter, however, does.
If you have to delete duplicate row. Then no need to set the order by clause.
Try below
Delete l from #LOG l
Inner Join
(
Select id from #LOG l
Inner Join(
Select user_id, event from #LOG
group by user_id, event
having COUNT(user_id) > 1 and COUNT(event) > 1
)T
on (l.user_id = t.user_id) and (l.event = t.event)
)T
on T.id = l.id