How to get the Average from two tables SQL - sql-server

I have 2 tables Denials_Scrub_Final and Claims_Final
I want to get the percent for all the invoice.
That would be (Denials_Scub_Final/Claims_Final) *100
This would display a new table Percentage as a new table.
This should look like the excel screenshot which was manually done.
Last block Denial Rate.

No final solution, but the approach should be clear.
Since we do not have the data from Denials_Scrub_Final or Claims_Final I generated some sample data. I am using a single table variable #data with some duplicates to generate the different numbers.
-- create sample data
declare #data table
(
Yr int,
Mth int,
Center nvarchar(10),
Invoice int
);
insert into #data (Yr, Mth, Center, Invoice) values
(2020, 1, 'ABC', 101),
(2020, 1, 'ABC', 101),
(2020, 1, 'ABC', 102),
(2020, 1, 'DEF', 201),
(2020, 1, 'DEF', 202),
(2020, 2, 'ABC', 103),
(2020, 2, 'ABC', 104),
(2020, 2, 'DEF', 203),
(2020, 3, 'ABC', 105),
(2020, 3, 'ABC', 105),
(2020, 3, 'ABC', 106),
(2020, 2, 'DEF', 204),
(2020, 2, 'DEF', 204),
(2020, 2, 'DEF', 205);
The first data set:
-- reproduce first query
select *
from ( select distinct Invoice, Center, Yr, Mth from #data ) BaseData
pivot ( count(Invoice) for Center in ([ABC], [DEF]) ) p;
gives
Yr Mth ABC DEF
----------- ----------- ----------- -----------
2020 1 2 2
2020 2 2 3
2020 3 2 0
The second data set:
-- reproduce second query
select *
from ( select Invoice, Center, Yr, Mth from #data ) BaseData
pivot ( count(Invoice) for Center in ([ABC], [DEF]) ) p;
gives
Yr Mth ABC DEF
----------- ----------- ----------- -----------
2020 1 3 2
2020 2 2 4
2020 3 3 0
Final solution: move the data sets in common table expressions (CTE's) and join them to apply the formula (use case to avoid division by zero and convert to format the percentages):
-- combine queries in CTE's and apply formula
with cte_denial as
(
select p.Yr, p.Mth, p.ABC, p.DEF
from ( select distinct Invoice, Center, Yr, Mth from #data ) BaseData
pivot ( count(Invoice) for Center in ([ABC], [DEF]) ) p
),
cte_claim as
(
select p.Yr, p.Mth, p.ABC, p.DEF
from ( select Invoice, Center, Yr, Mth from #data ) BaseData
pivot ( count(Invoice) for Center in ([ABC], [DEF]) ) p
)
select c1.Yr,
c1.Mth,
convert(numeric(5,2), case when c2.ABC > 0 then c1.ABC*100.0/c2.ABC else 0 end) as 'ABC_%',
convert(numeric(5,2), case when c2.DEF > 0 then c1.DEF*100.0/c2.DEF else 0 end) as 'DEF_%'
from cte_denial c1
join cte_claim c2
on c2.Yr = c1.Yr
and c2.Mth = c1.Mth;
gives
Yr Mth ABC_% DEF_%
----------- ----------- ---------- ----------
2020 1 66.67 100.00
2020 2 100.00 75.00
2020 3 66.67 0.00

Related

Add a Total row after each week

I am searching for a way to sum columns by week.
This is the initial table data.
Date WeekNo Col1 Col2 Col3
2020/07/01 27 1 4 3
2020/07/04 27 3 3 1
2020/07/06 28 1 1 1
2020/07/11 28 1 3 8
and I want to add a row total to every end of the week like this:
Date WeekNo Col1 Col2 Col3
2020/07/01 27 1 4 3
2020/07/04 27 3 3 1
TOTAL 27 4 7 4
2020/07/06 28 1 1 1
2020/07/11 28 1 3 8
TOTAL 28 2 4 9
I tried something similar the the code below but I have multiple columns to sum.
Do you have other ideas, suggestions?
Also, grouping sets does not create a new row if there is no data for that week to sum (like 0 or NULL).
SELECT
YEAR(Date) AS OrderYear,
MONTH(Date) AS OrderMonth,
SUM(Col1) AS SumCol1
FROM tb
GROUP BY
GROUPING SETS
(
YEAR(Date), --1st grouping set
(YEAR(Date),MONTH(Date)) --2nd grouping set
)
Is this what you are after?
My solution uses the built in with rollup addition to the group by clause.
-- create sample data
declare #data table
(
[Date] Date,
WeekNo int,
Col1 int,
Col2 int,
Col3 int
);
insert into #data ([Date], WeekNo, Col1, Col2, Col3) values
('2020-07-01', 27, 1, 4, 3),
('2020-07-04', 27, 3, 3, 1),
('2020-07-06', 28, 1, 1, 1),
('2020-07-11', 28, 1, 3, 8);
-- solution
select case when grouping(d.Date) = 0
then convert(nvarchar(10), d.Date) -- type conversion so all column values have the same type
else 'TOTAL'
end as 'Date',
d.WeekNo,
sum(d.Col1) as 'Col1',
sum(d.Col2) as 'Col2',
sum(d.Col3) as 'Col3'
from #data d
group by d.WeekNo, d.Date with rollup -- "roll up" the aggregations
having grouping(d.WeekNo) = 0; -- filter out aggregation across weeks
Gives me:
Date WeekNo Col1 Col2 Col3
---------- ----------- ----------- ----------- -----------
2020-07-01 27 1 4 3
2020-07-04 27 3 3 1
TOTAL 27 4 7 4
2020-07-06 28 1 1 1
2020-07-11 28 1 3 8
TOTAL 28 2 4 9
You only need to add (DATEPART(wk, Date)) as aggregation rule after listing the other non-aggregated columns Date,Col1, Col2, Col3. Btw, you do not need a WeekNo column, since it could already be computer by use of (DATEPART(wk, Date)).
So far so good, but ordering is such a daunting task as returning null values for WeekNo column for subtotal. I used two analytic functions ( ROW_NUMBER() and FISRT_VALUE() to overcome this problem ) :
SELECT COALESCE(Date,'TOTAL') As Date,
DATEPART(wk, Date) AS WeekNo,
SUM(Col1) AS Col1,
SUM(Col2) AS Col2,
SUM(Col3) AS Col3
FROM tb
GROUP BY GROUPING SETS ( ( Date,Col1, Col2, Col3 ),
(DATEPART(wk, Date))
)
ORDER BY CASE WHEN DATEPART(wk, Date) IS NULL
THEN
ROW_NUMBER() OVER (PARTITION BY DATEPART(wk, Date)
ORDER BY COALESCE(Date,'TOTAL') )
ELSE
DATEPART(wk, Date) -
FIRST_VALUE(DATEPART(wk, Date))
OVER ( ORDER BY COALESCE(Date,'TOTAL') ) + 1
END,
DATEPART(wk, Date)
Demo

TSQL: Continuous period for whole year / each month

I try to find all Cust who have membership for at least for one day in each month during 2018.
I came up with solution checking their membership at the beginning / middle / end end of each month like in snippet below, but trying to find more intelligent solution.
I know that I can use tally table for each of 365 days to check this but probably there is more elegant solution ? I'm bit new to SQL, I think I'm missing something in GROUPing area.
In the code snippet shown below, both Cust have at least one day membership.
Desired output:
CustID
------
1
22
Code:
with data as
(
select *
from (values (1, 1, '2017-12-11', '2018-01-16'), (1, 22, '2018-01-28', '2018-03-9' ), (1, 333, '2018-03-1', '2018-12-31') , -- island
(22, 1, '2017-12-31', '2018-01-11'), (22, 2, '2017-2-11', '2019-12-31')) as t (CustID, ContractID, StartDD, EndDD) ---
)
select
isdate(startDD), isdate(EndDD)
from
data
), gaps as
(
select
*,
datediff(day, lag(EndDD, 1, StartDD) over (partition by CustID order by StartDD), StartDD) as BreakDD -- negative is island
from
data
)
select
*,
datepart(month,StartDD) mmS , datepart(month,EndDD) mmE
from
gaps
-- and was active any 1+ day during each of the 12 months in 2018 ????
where
1 = 1
/* and (cast('1/1/2018' as date) between StartDD and EndDD
or cast('1/15/2018' as date) between StartDD and EndDD
or cast('1/31/2018' as date) between StartDD and EndDD)
---- etc.. for each month
and ( cast('12/1/2018' as date) between StartDD and EndDD
or cast('12/15/2018' as date) between StartDD and EndDD
or cast('12/31/2018' as date) between StartDD and EndDD
)
*/
--select CustID, max(BreakDD) Max_Days
--from gaps
--group by CustID
Try this answer.
First create a function to return all the month and year between the given dates.
Function:
--SELECT * FROM dbo.Fn_GetMonthYear('2017-12-11','2018-01-16')
ALTER FUNCTION dbo.Fn_GetMonthYear(#StartDate DATETIME,#EndDate DATETIME)
RETURNS TABLE
AS
RETURN(
SELECT DATEPART(MONTH, DATEADD(MONTH, x.number, #StartDate)) AS [Month]
,DATEPART(YEAR, DATEADD(MONTH, x.number, #StartDate)) AS [Year]
FROM master.dbo.spt_values x
WHERE x.type = 'P'
AND x.number <= DATEDIFF(MONTH, #StartDate, #EndDate)
)
Table Schema:
CREATE TABLE #t(CustID INT, ContractID INT, StartDD date, EndDD date)
INSERT INTO #t values (1, 1, '2017-12-11', '2018-01-16'), (1, 22, '2018-01-28', '2018-03-9' ), (1, 333, '2018-03-1', '2018-12-31') , -- island
(22, 1, '2017-12-31', '2018-01-11'), (22, 2, '2017-2-11', '2019-12-31')
Here is the T-SQL Query for your requirement.
SELECT CustID
,COUNT(DISTINCT [Month]) NoOfMonths
FROM(
SELECT *
FROM #t t
CROSS APPLY dbo.Fn_GetMonthYear(StartDD,EndDD)
)D
WHERE [Year] = 2018
GROUP BY CustID
HAVING COUNT(DISTINCT [Month])=12
Result:
CustID NoOfMonths
1 12
22 12
find all Cust who have membership for at least for one day in each
month during 2018
I think this mean that data must be present between '2018-01-01' and '2018-12-31' for each custid.
CREATE TABLE #t(CustID INT, ContractID INT, StartDD date, EndDD date)
INSERT INTO #t values (1, 1, '2017-12-11', '2018-01-16'), (1, 22, '2018-01-28', '2018-03-9' ), (1, 333, '2018-03-1', '2018-12-31') , -- island
(22, 1, '2017-12-31', '2018-01-11'), (22, 2, '2017-2-11', '2019-12-31')
declare #From Datetime='2018-01-01'
declare #To datetime='2018-12-31'
;with CTE as
(
select CustID,min(StartDD)StartDD
,max(EndDD)EndDD
from #t
group by CustID
)
select CustID,StartDD
,EndDD
from CTE
where StartDD<=#From and EndDD>=#To
This script is not tested across all sample data.
But logic is clear.So it can be corrected accordingly.
So tell for what sample data it is not working.

How do I aggregate on more than one column within a PIVOT

I have two Column Users and NewUsers I need to sum those two as Quarterly so I am using pivot function so I have written query below....
code is
select [week],[years],pivoting.[1] as Q1 ,pivoting.[2] AS Q2,pivoting.[3] AS Q3,pivoting.[4] AS Q4,pivoting.[1] as N1,pivoting.[2] AS N2,pivoting.[3] AS N3,pivoting.[4] AS N4 into #addpivot from
(
select Week,years,Quarter,users,NewUsers from #pivottable
) as PivotData
pivot
(
sum(users) for Quarter in ([1],[2],[3],[4])
) as pivoting
pivot
(
sum(NewUsers) for Quarter in ([1],[2],[3],[4])
) as pivoting
but it showing error in second line Quarter invalid column name
Where I am going wrong not able understand please help me.......
I dint understand what do you mean by multiple values ...
Pivot is as simple as this ...
SELECT *
FROM table
PIVOT( SUM(NewUsers) FOR Quarter IN ([1],[2],[3],[4]) ) AS PVTTable
If I've read your data correctly, you need to unpivot your data and add a column to identify the values to pivot on before pivoting. I've called this 'Category' and used CROSS APPLY but you can also use CASE.
SELECT * INTO #PivotTable FROM (
VALUES
(1, 1, 1, 10, 12),
(1, 1, 1, 11, 13),
(1, 1, 2, 8, 10),
(1, 1, 2, 7, 11),
(1, 1, 3, 11, 14),
(1, 1, 3, 8, 15),
(1, 1, 4, 15, 10),
(1, 1, 4, 17, 11)
)A (Week,Years,Quarter,Users,NewUsers)
SELECT * FROM
(SELECT Week
,Years
,Category
,Value FROM #PivotTable
CROSS APPLY
(SELECT 'NewUsersQ'+CONVERT(VARCHAR(1),Quarter) Category, NewUsers Value
UNION ALL
SELECT 'UsersQ'+CONVERT(VARCHAR(1),Quarter) Category, Users Value
) A
) SRC
PIVOT (
SUM(Value) FOR Category IN
([UsersQ1], [NewUsersQ1], [UsersQ2], [NewUsersQ2], [UsersQ3], [NewUsersQ3], [UsersQ4], [NewUsersQ4])
)Pvt
Week Years UsersQ1 NewUsersQ1 UsersQ2 NewUsersQ2 UsersQ3 NewUsersQ3 UsersQ4 NewUsersQ4
----------- ----------- ----------- ----------- ----------- ----------- ----------- ----------- ----------- -----------
1 1 21 25 15 21 19 29 32 21
SELECT [week]
,[years]
,SUM(CASE WHEN Quarter = 1 THEN users ELSE 0 END) AS Q1
,SUM(CASE WHEN Quarter = 2 THEN users ELSE 0 END) AS Q2
,SUM(CASE WHEN Quarter = 3 THEN users ELSE 0 END) AS Q3
,SUM(CASE WHEN Quarter = 4 THEN users ELSE 0 END) AS Q4
,SUM(CASE WHEN Quarter = 1 THEN NewUsers ELSE 0 END) AS N1
,SUM(CASE WHEN Quarter = 2 THEN NewUsers ELSE 0 END) AS N2
,SUM(CASE WHEN Quarter = 3 THEN NewUsers ELSE 0 END) AS N3
,SUM(CASE WHEN Quarter = 4 THEN NewUsers ELSE 0 END) AS N4
FROM #pivottable
GROUP BY [week]
,[years]

How to create a Matrix table on SQL from another table

I have the following table with the following columns.
-------------------------------------
Column1 | Column2 | TotalCount
--------------------------------------
1 1 40
1 2 50
2 1 10
2 2 60
Also, I have another table that is related to Column1 where 1 is X and 2 is Y and same for Column2 where 1 is A and 2 is B
I am trying to come up with a SQL statement that basically gives me some view like...
--------------------
ColumnName | A | B
--------------------
X 40 50
Y 10 60
Any idea how can I achieve that? I've been trying to pivot the data with no luck.
Thanks!
Full working example:
DECLARE #DataSource TABLE
(
[Column1] TINYINT
,[Column2] TINYINT
,[TotalCount] TINYINT
);
INSERT INTO #DataSource ([Column1], [Column2], [TotalCount])
VALUES (1, 1, 40)
,(1, 2, 50)
,(2, 1, 10)
,(2, 2, 60);
SELECT *
FROM
(
SELECT IIF([Column1] = 1, 'X', 'Y') AS [ColumnName]
,IIF([Column2] = 1, 'A', 'B') AS [Column2]
,[TotalCount]
FROM #DataSource
) DS
PIVOT
(
MAX([TotalCount]) FOR [Column2] IN ([A], [B])
) PVT;
Using conditional aggregation:
WITH tbl AS(
SELECT * FROM ( VALUES
(1, 1, 40), (1, 2, 50),
(2, 1, 10), (2, 2, 60)
)t(Column1, Column2, TotalCount)
)
SELECT
ColumnName = CASE WHEN Column1 = 1 THEN 'X' ELSE 'Y' END,
A = MAX(CASE WHEN Column2 = 1 THEN TotalCount END),
B = MAX(CASE WHEN Column2 = 2 THEN TotalCount END)
FROM tbl
GROUP BY Column1
RESULT:
ColumnName A B
---------- ----------- -----------
X 40 50
Y 10 60

Unpivot table data

Sno Water Milk
1 50 100
2 22 120
3 11 142
i have this table.Now i want result like
Sno Type Qnty
1 Water 83
2 Milk 362
How can I please tell me.
SQL Server 2008 does not support this kind of statement.
You can achieve that in 2 ways:
using temporary table (variable type table)
DECLARE #products TABLE(Sno INT, Water INT, Milk INT)
INSERT INTO #products
VALUES (1, 50, 100), (2, 22, 120), (3, 11, 142)
SELECT ROW_NUMBER() OVER(ORDER BY SUM(Qnty)) AS RowNo, Product, SUM(Qnty) AS Qnty
FROM (
SELECT Product, Qnty
FROM (
SELECT *
FROM #products
) AS pvt
UNPIVOT (Qnty FOR Product IN ([Water],[Milk])) AS unpvt
) AS T
GROUP BY Product</pre>
or
;WITH T AS
(
SELECT Sno, Water, Milk
FROM (
SELECT 1 AS Sno, 50 AS Water, 100 AS Milk
UNION ALL
SELECT 2, 22, 120
UNION ALL
SELECT 3, 11, 142
) t (Sno, Water, Milk))
SELECT Sno = ROW_NUMBER() OVER(ORDER BY SUM(Upvt.Qnty)),
upvt.Type,
Qnty = SUM(Upvt.Qnty)
FROM T
UNPIVOT
( Qnty
FOR Type IN ([Water], [Milk])
) upvt
GROUP BY upvt.Type
ORDER BY Qnty;</pre>
Please,refer MSDN documentation.
The first step is to UNPIVOT your data:
WITH T AS
( SELECT Sno, Water, Milk
FROM (VALUES (1, 50, 100), (2, 22, 120), (3, 11, 142)) t (Sno, Water, Milk)
)
SELECT upvt.Sno,
upvt.Type,
Upvt.Qnty
FROM T
UNPIVOT
( Qnty
FOR Type IN ([Water], [Milk])
) AS upvt;
Which will give:
Sno Type Qnty
1 Water 50
1 Milk 100
2 Water 22
2 Milk 120
3 Water 11
3 Milk 142
You can then apply normal aggregation to this result:
WITH T AS
( SELECT Sno, Water, Milk
FROM (VALUES (1, 50, 100), (2, 22, 120), (3, 11, 142)) t (Sno, Water, Milk)
)
SELECT Sno = ROW_NUMBER() OVER(ORDER BY SUM(Upvt.Qnty)),
upvt.Type,
Qnty = SUM(Upvt.Qnty)
FROM T
UNPIVOT
( Qnty
FOR Type IN ([Water], [Milk])
) AS upvt
GROUP BY upvt.Type
ORDER BY Qnty;
Giving:
Sno Type Qnty
1 Water 83
2 Milk 362
EDIT
Based on your comment that you are using SQL Server 2005, not 2008 as indicated below is a full working example that will work on 2005:
DECLARE #T TABLE (Sno INT, Water INT, Milk INT);
INSERT #T (Sno, Water, Milk) VALUES (1, 50, 100);
INSERT #T (Sno, Water, Milk) VALUES(2, 22, 120);
INSERT #T (Sno, Water, Milk) VALUES(3, 11, 142);
SELECT Sno = ROW_NUMBER() OVER(ORDER BY SUM(Upvt.Qnty)),
upvt.Type,
Qnty = SUM(Upvt.Qnty)
FROM #T AS T
UNPIVOT
( Qnty
FOR Type IN ([Water], [Milk])
) AS upvt
GROUP BY upvt.Type
ORDER BY Qnty;
It was the table valued constructor I was using to create the sample data that was causing the error in 2005, nothing to do with the actual query that unpivots then sums the data.
This gives the result you asked for but I get the idea you want something a little more advanced. If so please elaborate.
SELECT 'water', sum(water) FROM table_name
UNION ALL
SELECT 'milk', sum(milk) FROM table_name

Resources