SQL Query assistance using Pivot - sql

I have a table as follows:
PriorityText Priority LoRes Partial Unknown N_A HiRes
------------------------------------------------------------------
Very High 5 0.0612 0.0000 0.0612 0.0612 0.2041
High 4 0.1429 0.0000 0.1633 0.0000 0.1633
Medium 3 0.0000 0.0000 0.1020 0.0000 0.0408
Low-Medium 2 0.0000 0.0000 0.0000 0.0000 0.0000
Low 1 0.0000 0.0000 0.0000 0.0000 0.0000
I am tying to transpose the tbale into this:
PriorityText Low Low-Medium Medium High Very High
--------------------------------------------------------
Priority 1 2 3 4 5
LoRes 0 0 0 0.1429 0.0612
Partial 0 0 0 0 0
Unknown 0 0 0.102 0.1633 0.0612
N_A 0 0 0 0 0.0612
HiRes 0 0 0.0408 0.1633 0.2041
I am using SQL 2008. I am habing trouble coming up with the SQL syntax to perform a pivot on the data.
Can someone please share a SQL snippet that will solve this for me?
I have used the following to successfully pivot one row, but I do not know how to make it do all my rows.
SELECT VeryHigh AS VeryHigh,
High AS High,
Medium AS Medium,
[Low-Medium] AS [Low-Medium],
Low AS Low
FROM (SELECT [PriorityText], [LoRes], [Low-Medium], [Medium], [High], [VeryHigh]
FROM #tbTemp) p
PIVOT (SUM(LoRes) FOR [PriorityText] in ([VeryHigh], [High], [Medium], [Low-Medium], [Low])) pvt
My test data in my table is as follows:
Priority PriorityText LoRes Partial Unknown N_A HiRes
1 VeryHigh 0.05 11 54 0 9
2 High 0.14 22 54 0 3
3 Medium 0.07 33 65 0 7
4 Low-Medium 0.01 44 87 0 4
5 Low 0 55 9 0 0
NULL NULL NULL NULL NULL NULL NULL
Thank for any help!!

You need to UNPIVOT data and then re-PIVOT values using desired column heads:
SELECT pvt.*
FROM
(
SELECT unpvt.PriorityText
,unpvt.PriorityText2
,unpvt.MyValueMyValue
FROM SourceTable src
UNPIVOT( MyValueMyValue FOR PriorityText2 IN ([Priority],[LoRes],[Partial],[Unknown],[N_A],[HiRes]) ) unpvt
) src2
PIVOT( MAX(src2.MyValueMyValue) FOR src2.PriorityText IN ([Low],[Low-Medium],[Medium],[High],[Very High]) ) pvt

This solution is kind of ugly, but i think it will do what you are asking for and is pretty straight forward.
There are more elegant and dynamic ways to transpose data with dynamic sql and with xml.
for example http://sql-tricks.blogspot.com/2011/04/sql-server-rows-transpose.html
-- POPULATE SAMPLE DATA
DECLARE #tbTemp table (PriorityText varchar(50), Priority float, LoRes float, Partial float, Unknown float, N_A float, HiRes float)
insert into #tbTemp (PriorityText,Priority,LoRes,Partial,Unknown,N_A, HiRes)
values
('Very High',5,0.0612,0.0000,0.0612,0.0612,0.2041),
('High',4,0.1429,0.0000,0.1633,0.0000,0.1633),
('Medium',3,0.0000,0.0000,0.1020,0.0000,0.0408),
('Low-Medium',2,0.0000,0.0000,0.0000,0.0000,0.0000),
('Low',1,0.0000,0.0000,0.0000,0.0000,0.0000)
;
with sourcetable ([Key],ColumnName,Value) -- Transposing into key/value-pair for each column
as
(
select 'Priority', PriorityText, Priority from #tbTemp
union all
select 'LoRes', PriorityText, LoRes from #tbTemp
union all
select 'Partial', PriorityText, Partial from #tbTemp
union all
select 'Unknow', PriorityText, Unknown from #tbTemp
union all
select 'N_A', PriorityText, N_A from #tbTemp
union all
select 'HiRes', PriorityText, HiRes from #tbTemp
)
select
grouptable.PriorityText,
(select Value from sourcetable
where sourcetable.ColumnName = 'Low'
and sourcetable.[Key] = grouptable.PriorityText) as Low,
(select Value from sourcetable
where sourcetable.ColumnName = 'Low-Medium'
and sourcetable.[Key] = grouptable.PriorityText) as [Low-Medium],
(select Value from sourcetable
where sourcetable.ColumnName = 'Medium'
and sourcetable.[Key] = grouptable.PriorityText)as Medium,
(select Value from sourcetable
where sourcetable.ColumnName = 'High'
and sourcetable.[Key] = grouptable.PriorityText) as High,
(select Value from sourcetable
where sourcetable.ColumnName = 'Very High'
and sourcetable.[Key] = grouptable.PriorityText) as [Very High]
from (
select 'Priority' as PriorityText
union all
select 'LoRes' as PriorityText
union all
select 'Partial' as PriorityText
union all
select 'Unknow' as PriorityText
union all
select 'N_A' as PriorityText
union all
select 'HiRes' as PriorityText
) grouptable -- Creating each row

Related

Calculating new percentages over total in a "select distinct" query with multiple percentages rows

The title may be puzzling, but the situation should be really simple foranyone reading the following lines.
I have this table VAL:
customer month_1 month_2 month_3 value
ABC 0.5 0 0.50 200
ABC 0.25 0.25 0.50 200
XYZ 1 0 0 150
RST 0 0 1 200
RST 0 0.50 0.50 130
(This is the code to get it)
create table VAL (customer nvarchar(255), month_1 decimal(18,2), month_2 decimal(18,2), month_3 decimal(18,2), value decimal(18,2))
insert into VAL values ('ABC', 0.5, 0 , 0.50, 200)
insert into VAL values ('ABC',0.25 , 0.25, 0.50 , 200 )
insert into VAL values ('XYZ', 1 , 0 , 0 , 150 )
insert into VAL values ('RST', 0 , 0 , 1 , 200 )
insert into VAL values ('RST', 0 , 0.50, 0.50 , 130 )
This can be seen (transforming what is a percentage in actual values) as
customer value_month_1 value_month_2 value_month_3 value
ABC 100 0 100 200
ABC 50 50 100 200
XYZ 150 0 0 150
RST 0 0 200 200
RST 0 65 65 130
I need to transform everything in the following table, that is sort of a collapsed version of the first one:
customer month_1 month_2 month_3 value
ABC 0.375 0.125 0.50 400
XYZ 1.0 0 0.0 150
RST 0.0 0.197 0.793 330
So far, I'm able to do this customer by customer with the following code:
select distinct customer
,sum(month_1) as month_1
,sum(month_2) as month_2
,sum(month_3) as month_3
,sum(value) as value
from (
select distinct customer
,month_1 * sum(value)/(select sum(value) from VAL where customer='ABC' group by customer) as month_1
,month_2 * sum(value)/(select sum(value) from VAL where customer='ABC' group by customer) as month_2
,month_3 * sum(value)/(select sum(value) from VAL where customer='ABC' group by customer) as month_3
,sum(value) as value from VAL where customer='ABC' group by customer, month_1, month_2,month_3) as NEW
group by customer
that gives me the following result:
customer month_1 month_2 month_3 value
ABC 0.375 0.125 0.50 400
I'm pretty sure there are better ways to do this, probably with some command I don't know very well how to use.
Anyone able to help?
You just need a weighted average:
select customer,
sum(month_1 * value) / sum(value) as month_1,
sum(month_2 * value) / sum(value) as month_2,
sum(month_3 * value) / sum(value) as month_3,
sum(value)
from val
group by customer;

TSQL order by group for monthly reports

I have court clearance statistic to made, but i have some slight problem with my monthly.. it didt follow in order, and wish someone could help me fix it.. and is it possible to add total in my table?
DECLARE #StartDate As date = '03-28-2015',
#EndDate As date = '03-28-2015'
DECLARE #TEMP_DATES AS TABLE (FROM_DATE DATE, TO_DATE DATE)
INSERT INTO #TEMP_DATES VALUES(#StartDate, #EndDate)
DECLARE #TENP_MONTH_YEAR AS TABLE(MONTH_YEAR VARCHAR(20), [YEAR] INT, [MONTH] INT)
INSERT INTO #TENP_MONTH_YEAR
select FORMAT(D.Dates, 'MMMM-yy', 'en-US' ) AS MonthYear, YEAR(D.Dates), MONTH(D.Dates)
from #TEMP_DATES as T
inner join master..spt_values as N
on N.number between 0 and datediff(DAY, T.FROM_DATE, T.TO_DATE)
cross apply (select dateadd(DAY, N.number, T.FROM_DATE)) as D(Dates)
where N.type ='P'
GROUP BY FORMAT(D.Dates, 'MMMM-yy', 'en-US' ), YEAR(D.Dates), MONTH(D.Dates)
ORDER BY YEAR(D.Dates), MONTH(D.Dates)
DECLARE #NEWID AS UNIQUEIDENTIFIER = NEWID()
SELECT CT.RPT_CASE_CODE_GROUP, SUM(ISNULL(INCOMING_CASES, 0)) AS INCOMING_CASES, SUM(ISNULL(OUTGOING_CASES, 0)) AS OUTGOING_CASES,
ISNULL(CAST(SUM(NULLIF(CAST(ISNULL(OUTGOING_CASES, 0) AS DECIMAL),0.00))/SUM(NULLIF(CAST(ISNULL(INCOMING_CASES, 0) AS DECIMAL),0.00)) * 100 AS DECIMAL(18,2)),0) AS [CLEARANCE_RATE],
MONTH_YEAR
FROM #tempClearanceListCases tempCLC
RIGHT OUTER JOIN (SELECT CASE_TYPE_ID, MONTH_YEAR, [YEAR], [MONTH]
FROM (SELECT DISTINCT CASE_TYPE_ID FROM #tempClearanceListCases tempCLC ) A, #TENP_MONTH_YEAR tempMonthYear) B
ON B.CASE_TYPE_ID = tempCLC.CASE_TYPE_ID AND tempCLC.MONTHLY = B.MONTH_YEAR
INNER JOIN CaseType CT WITH (NOLOCK)
ON B.CASE_TYPE_ID = CT.CASE_TYPE_ID
WHERE ISNULL(COURT_LOCATION_ID, #NEWID) = ISNULL(#COURT_LOCATION_ID, ISNULL(COURT_LOCATION_ID, #NEWID))
GROUP BY CT.RPT_CASE_CODE_GROUP, [INTERVAL_MONTH], MONTH_YEAR
ORDER BY CT.RPT_CASE_CODE_GROUP
The result which is the monthly is not correct order:
RPT_CASE_CODE_GROUP | INCOMEING CASES | OUTGOING CASES | CLEARANCERATE | MONTHYEAR
BCY/CP 15 4 26.67 March-15
BCY/CP 15 0 0.00 February-15
BCY/CP 33 0 0.00 January-15
BCY/DP 0 0 0.00 February-15
BCY/DP 2 0 0.00 March-15
BCY/DP 1 0 0.00 January-15
The result atleast i want it to be :
RPT_CASE_CODE_GROUP | INCOMEING CASES | OUTGOING CASES | CLEARANCERATE | MONTHYEAR
BCY/CP 33 0 0.00 January-15
BCY/CP 15 0 0.00 February-15
BCY/CP 15 4 26.67 March-15
BCY/DP 1 0 0.00 January-15
BCY/DP 0 0 0.00 February-15
BCY/DP 2 0 0.00 March-15
The result i want :
RPT_CASE_CODE_GROUP | INCOMEING CASES | OUTGOING CASES | CLEARANCERATE | MONTHYEAR
BCY/CP 33 0 0.00 January-15
BCY/CP 15 0 0.00 February-15
BCY/CP 15 4 26.67 March-15
63 4 6.34 Overall
BCY/DP 1 0 0.00 January-15
BCY/DP 0 0 0.00 February-15
BCY/DP 2 0 0.00 March-15
3 0 0.00 Overall
DO i have to stick to my query or create grouping query? i already spend many hour on this, i feel hard to turn back, im fresh grad :( can any guru guide me?
if all your MONTHYEAR are following the sames patter monthname-xx you can use following statement on order:
ORDER BY
cast('20' + substring(MONTHYEAR, Charindex('-', MONTHYEAR) + 1, 2) + '-' + substring(MONTHYEAR, 1, 3) + '-01' AS date)
This looks like a job for the UNION clause. It seems like you should have this execution order for the results you want:
SELECT -- data you want from tables w/ all joins
WHERE RPT_CASE_CODE_GROUP = 'BCY/CP'
UNION ALL
SELECT '', SUM([INCOMING CASES]), SUM([OUTGOING CASES]), AVG([CLEARANCE RATE], 'Overall'
FROM -- source data
WHERE RPT_CASE_CODE_GROUP = 'BCY/CP'
UNION ALL
SELECT -- data you want from tables w/ all joins
WHERE RPT_CASE_CODE_GROUP = 'BCY/DP'
UNION ALL
SELECT '', SUM([INCOMING CASES]), SUM([OUTGOING CASES]), AVG([CLEARANCE RATE], 'Overall'
FROM -- source data
WHERE RPT_CASE_CODE_GROUP = 'BCY/CP'
Alternatively, if there are more RPT_CASE_CODE_GROUP values than the one presented, you can use a loop to capture information about all of them like this:
CREATE TABLE #rccg(ID INT IDENTITY(1,1), RPT_CASE_CODE_GROUP NVARCHAR(15))
INSERT INTO #rccg(RPT_CASE_CODE_GROUP)
SELECT DISTINCT RPT_CASE_CODE_GROUP FROM --data source
DECLARE #i INT = 1, #j INT = (SELECT MAX(ID) FROM #rccg), #rccg NVARCHAR(15)
DECLARE #results TABLE(rccg NVARCHAR(15), ic INT, oc INT, cr INT, my NVARCHAR(20))
WHILE #i < #j
BEGIN
SET #rccg = (SELECT RPT_CASE_CODE_GROUP FROM #rccg WHERE ID = #i)
INSERT INTO #results
SELECT -- data you want from tables w/ all joins
WHERE RPT_CASE_CODE_GROUP = #rccg
UNION ALL
SELECT '', SUM([INCOMING CASES]), SUM([OUTGOING CASES]), AVG([CLEARANCE RATE], 'Overall'
FROM -- source data
WHERE RPT_CASE_CODE_GROUP = #rccg
END
SELECT * FROM #rccg
DROP TABLE #rccg
I know I didn't use your specific code, because that would have taken up a huge amount of space, but I think you get the general idea. For each field you want the totals of for the time period, you use the SUM(column_name) aggregate function. You can get a pretty good explanation and examples here: http://www.techonthenet.com/sql/sum.php.
I hope this at least helps point you in the right direction.

SQL See Whether Two or More Columns In a Table is Greater Than 0

I have ran in to a little problem and would appreciate any help.
My Table is such:
CASH | CREDIT CARD | DEBIT CARD | ACCOUNT | OTHER
-------------------------------------------------
0.00 0.00 0.00 0.00 0.00
1.00 0.00 0.00 0.00 0.00
2.00 1.00 0.00 0.00 0.00
My aim is to SELECT * FROM any of the above rows that have more than one column > 0.
So the third row would be selected in this scenario with the above table.
SELECT
[CASH], [CREDIT CARD], [DEBIT CARD], [ACCOUNT], [OTHER]
FROM table
WHERE
CASE WHEN [CASH] > 0 THEN 1 ELSE 0 END+
CASE WHEN [CREDIT CARD] > 0 THEN 1 ELSE 0 END+
CASE WHEN [DEBIT CARD] > 0 THEN 1 ELSE 0 END+
CASE WHEN [ACCOUNT] > 0 THEN 1 ELSE 0 END+
CASE WHEN [OTHER] > 0 THEN 1 ELSE 0 END >= 2
I prefer t-clausen's answer but just as an exercise, I decide to try it as an UNPIVOT followed by a PIVOT, so that we could write it using more of the general SQL tools:
declare #t table (SomeID int,Cash money,Credit money,Debit money,Account money,Other money)
insert into #t(SomeID,Cash,Credit,Debit,Account,Other) values
(1,0.00,0.00,0.00,0.00,0.00),
(2,1.00,0.00,0.00,0.00,0.00),
(3,2.00,1.00,0.00,0.00,0.00)
;With Unpiv as (
select *,SUM(CASE WHEN MoneyValue > 0.00 THEN 1 ELSE 0 END) OVER (PARTITION BY SomeID) as cnt
from #t t
unpivot (MoneyValue for MoneyType in (Cash,Credit,Debit,Account,Other)) x
), Repiv as (
select *
from Unpiv u
pivot (SUM(MoneyValue) for MoneyType in (Cash,Credit,Debit,Account,Other)) x
where
cnt >= 2
)
select * from Repiv
This does assume that you've got another column (here, called SomeID) by which each row can be uniquely identified.
Result:
SomeID cnt Cash Credit Debit Account Other
----------- ----------- --------------------- --------------------- --------------------- --------------------- ---------------------
3 2 2.00 1.00 0.00 0.00 0.00
Just hoping the above might be more adaptable for some variants of the requirements.
SELECT
[CASH], [CREDIT CARD], [DEBIT CARD], [ACCOUNT], [OTHER]
FROM table
WHERE (
SELECT COUNT(*)
FROM (VALUES ([CASH]),([CREDIT CARD]),([DEBIT CARD]),([ACCOUNT]),([OTHER])) t(value)
WHERE value > 0
) >= 2

SQL query to calculate interval discount

I have trouble understanding how I can solve this problem with a T-SQL query.
I have a price column and a volume column. In another table a have discounts at different levels of volume. So my discount table could have values as
(StartLevel, DiscountFactor)
(0, 1);
(25, 0.95);
(50, 0.90);
(100, 0.75)
What I want is to calculate a total price. If Volume is 35, I want it to multiply
Price x ((35-25) x 0.95 + (25-0) x 1)
If the volume is 200, it should be
Price x ((200-100) x 0.75 + (100-50) x .9+(50-25) x .95+(25) x 1)
Can anybody help me with a query that solves this?
This can help:
DECLARE #products TABLE
(
id INT ,
price MONEY ,
volume INT
)
DECLARE #discounts TABLE
(
id INT ,
Level INT ,
Factor MONEY
)
INSERT INTO #products
VALUES ( 1, 10, 35 ),
( 2, 15, 200 )
INSERT INTO #discounts
VALUES ( 1, 0, 1 ),
( 2, 25, 0.95 ),
( 3, 50, 0.90 ),
( 4, 100, 0.75 )
SELECT p.id, p.price * SUM(ca.m)
FROM #products p
CROSS APPLY ( SELECT * ,
Factor * ( -Level + LEAD(Level) OVER ( PARTITION BY p.id ORDER BY Level, d ) ) AS m
FROM ( SELECT 1 AS d ,
Level ,
Factor
FROM #discounts
WHERE Level < p.volume
UNION ALL
SELECT 2 AS d ,
p.volume ,
0
) t
) ca
GROUP BY p.id, p.price
Without grouping it returns:
id price volume d Level Factor m
1 10.00 35 1 0 1.00 25.00
1 10.00 35 1 25 0.95 9.50
1 10.00 35 2 35 0.00 NULL
2 15.00 200 1 0 1.00 25.00
2 15.00 200 1 25 0.95 23.75
2 15.00 200 1 50 0.90 45.00
2 15.00 200 1 100 0.75 75.00
2 15.00 200 2 200 0.00 NULL
Then just group by product and sum of m results in:
id Total
1 345.00
2 2531.25
For a given Volume and Price you can get the discount based on interval using LEAD which is available in SQL Server 2012+ onwards.
Sample Data
DECLARE #PriceTable TABLE(Volume INT,Price DECIMAL(9,2) )
DECLARE #Discount TABLE(StartLevel int, DiscountFactor DECIMAL(9,2))
INSERT INTO #PriceTable
VALUES(75, 20.5),
(150, 20),
(250, 20.5),
(0, 15);
INSERT INTO #Discount
VALUES(0, 1),
(25, 0.95),
(50, 0.90),
(100, 0.75);
Query
SELECT Volume,Price,FinalPrice
FROM #PriceTable P
CROSS APPLY(
SELECT SUM(CASE WHEN (MaxLevel >=StartLevel) THEN (MaxLevel-StartLevel) ELSE 0 END *DiscountFactor)*P.Price as FinalPrice
FROM
(
SELECT CASE WHEN LEAD(StartLevel)OVER(ORDER BY StartLevel) < P.Volume THEN LEAD(StartLevel)OVER(ORDER BY StartLevel) ELSE P.Volume END MaxLevel,StartLevel, DiscountFactor
FROM #Discount
) IQ
)T
Output
Volume Price FinalPrice
75 20.50 1460.6250
150 20.00 2625.0000
250 20.50 4228.1250
0 15.00 0.0000

TSQL Recursive CTE That Contains a SUM

I have a table called T that has three rows as follows....
Id allocation multiplier multipliedallocation multipliedallocationsum
1 20.000 1.0008 20.016 100.052
2 50.000 1.0006 50.030 100.052
3 30.000 1.0002 30.006 100.052
I would like to use this table to produce some projection results that alter the allocation over a number of months as follows...
Id allocation multiplier multipliedallocation multipliedallocationsum mnth
1 20.000 1.0008 20.016 100.052 1
2 50.000 1.0006 50.030 100.052 1
3 30.000 1.0002 30.006 100.052 1
1 20.005 1.0008 20.021 100.050 2
2 50.003 1.0006 50.033 100.050 2
3 29.990 1.0002 29.996 100.050 2
1 20.011 1.0008 20.027 100.052 3
2 50.008 1.0006 50.038 100.052 3
3 29.981 1.0002 29.987 100.052 3
1 20.017 1.0008 20.033 100.054 4
2 50.012 1.0006 50.042 100.054 4
3 29.971 1.0002 29.979 100.054 4
etc
The multipliedallocation on any row = the allocation x multiplier.
The multipliedallocationsum on any row = the sum of the multipliedallocation for that month
The allocation for month n is the multipliedallocation for month n-1 divided by the multipliedallocationsum for month n-1, multiplied by 100
This is the recursive cte SQL statement I have come up with so far, but it is not doing what I expect...
WITH Alloc (Id, allocation, multiplier, multipliedallocation, mnth)
AS
(
SELECT Id, allocation, multiplier, allocation * multiplier AS multipliedallocation, 1 AS mnth
FROM T
),
AllocProjected (Id, allocation, multiplier, multipliedallocation, multipliedallocationsum, mnth)
AS
(
SELECT a.Id, a.allocation, a.multiplier, a.multipliedallocation,
SUM(a.multpliedallocation) OVER (PARTITION BY a.Id, a.mnth), 1
FROM Alloc a
UNION ALL
SELECT a.Id,
CONVERT(decimal(6,3), (a.multipliedallocation / a.multipliedallocationsum) * 100.0) AS allocation,
a.multiplier AS multiplier,
a.multiplier,
a.multiplier * (a.multipliedallocation / a.multipliedallocationsum) * 100.0 AS multipliedallocation,
SUM(a.multipliedallocation) OVER (PARTITION BY a.mnth) AS multipliedallocationsum,
a.mnth + 1
FROM AllocProjected a
WHERE a.mnth < 24
)
SELECT * FROM AllocProjected
ORDER BY mnth
the multipliedallocationsum only seems to show multipliedallocation for a single row, not the sum of the multipliedallocation for the whole month (i.e. across 3 rows)