T-SQL applying pivot for two rows under a single column - sql-server

On SQL Server 2014 I use the following code:
CREATE TABLE TempTable
(
LType varchar(255),
LStatus varchar(255),
PAmount decimal(16,2),
RAmount decimal(16,2));
INSERT INTO TempTable (LType, LStatus, PAmount, RAmount)
VALUES ('TypeA','StatusA', '1000', '10'),
('TypeB', 'StatusC', '500', '50'),
('TypeC', 'StatusB', '2500', '100'),
('TypeB', 'StatusB', '1000', '50'),
('TypeA', 'StatusA', '3000', '25'),
('TypeC', 'StatusB', '2200', '50');
Select Ltype, Lstatus, SUM(PAmount) as PAmount, SUM(RAmount) as RAmount
From TempTable
Where PAmount > 0
Group By LType, LStatus
to get this table:
What I’m trying to achieve is:
I used pivot but was unable to apply it simultaneously for PAmount and RAmount under Status columns.
Can anyone help with solution?

You can use conditional aggregation for this. This assumes you will always have these values. If you need this to be dynamic then there is a bit more work to do.
select StatusA_PAMount = max(case when Totals.Lstatus = 'StatusA' then Totals.PAmount end)
, StatusA_RAMount = max(case when Totals.Lstatus = 'StatusA' then Totals.RAmount end)
, StatusB_PAMount = max(case when Totals.Lstatus = 'StatusB' then Totals.PAmount end)
, StatusB_RAMount = max(case when Totals.Lstatus = 'StatusB' then Totals.RAmount end)
, StatusC_PAMount = max(case when Totals.Lstatus = 'StatusC' then Totals.PAmount end)
, StatusC_RAMount = max(case when Totals.Lstatus = 'StatusC' then Totals.RAmount end)
from
(
Select Lstatus
, SUM(PAmount) as PAmount
, SUM(RAmount) as RAmount
From TempTable
Where PAmount > 0
Group By LStatus
) Totals

Related

Subquery a Cast Function

I have the following code which I'm using to transpose some data (see below); however, when running the code I received a 'Operand data type datetime2 is invalid for sum operator' error, which I believe is due to the fact the [RESULT_DT_TM] column has both date and time values. With the help from the outstanding contributors, I made what turns out to be a very simple code that removes the date from the [RESULT_DT_TM]:
select cast([RESULT_DT_TM] as time (0)) as [result_dt]
from ED_Vitals_Import_Master
I would like to include this code within the main query so I have use the new [result_dt] variable but am having trouble embedding it. Is it possible to do what I am seeking?
Select *
From (
Select a.[PT_FIN]
,B.*
From (Select *,RN=Row_Number() over (Partition By PT_FIN Order by [RESULT_DT_TM]) From ED_Vitals_Import_Master ) A
Cross Apply (values (concat('Time' ,RN),[RESULT_DT_TM])
,(concat('Weight' ,RN),[WEIGHT_RESULT])
,(concat('SysBp' ,RN),[SYSBP_RESULT])
,(concat('DiaBP',RN),[DIABP_RESULT])
,(concat('Temp' ,RN),[TEMPERATURE_RESULT])
,(concat('Oxy' ,RN),[OXYGEN_SAT_RESULT])
,(concat('Fio' ,Rn),[FIO2_RESULT])
) B(Item,Value)
) src
Pivot (sum(Value) for Item in ([RESULT_DT_TM1],[Weight1],[Sysbp1],[DiaBP1], [Temp1], [Oxy1], [Fio1]
,[RESULT_DT_TM2],[Weight2],[Sysbp2],[DiaBP2], [Temp2], [Oxy2], [Fio2]
,[RESULT_DT_TM3],[Weight3],[Sysbp3],[DiaBP3], [Temp3], [Oxy3], [Fio3]
,[RESULT_DT_TM4],[Weight4],[Sysbp4],[DiaBP4], [Temp4], [Oxy4], [Fio4]
) ) pvt
Since you are mixing datatypes... perhaps a conditional aggregation would be more useful.
Example
Select a.[PT_FIN]
,[RESULT_DT_TM1] = max(case when RN=1 then [RESULT_DT_TM] end)
,[Weight1] = max(case when RN=1 then [Weight] end)
,[Sysbp1] = max(case when RN=1 then [Sysbp] end)
,[DiaBP1] = max(case when RN=1 then [DiaBP] end)
,[Temp1] = max(case when RN=1 then [Temp] end)
,[Oxy1] = max(case when RN=1 then [Oxy] end)
,[Fio1] = max(case when RN=1 then [Fio] end)
,[RESULT_DT_TM2] = max(case when RN=2 then [RESULT_DT_TM] end)
,[Weight2] = max(case when RN=2 then [Weight] end)
,[Sysbp2] = max(case when RN=2 then [Sysbp] end)
,[DiaBP2] = max(case when RN=2 then [DiaBP] end)
,[Temp2] = max(case when RN=2 then [Temp] end)
,[Oxy2] = max(case when RN=2 then [Oxy] end)
,[Fio2] = max(case when RN=2 then [Fio] end)
--- Extend the Groups Here ---
From (Select *,RN=Row_Number() over (Partition By PT_FIN Order by [RESULT_DT_TM]) From ED_Vitals_Import_Master ) A
Group By a.[PT_FIN]

Convert vertical table to horizontal in SQL Server

I have a large table that has 8 row numbers with an associated loss and carrier. I am trying to convert into a horizontal structure.
CREATE TABLE #mytable
(
[ID] int NULL,
[RowNum] bigint NULL,
[Loss] float NULL,
[Carrier] nvarchar(255) NULL
)
INSERT INTO #mytable ([ID], [RowNum], [Loss], [Carrier])
VALUES (1,1, 0, 'test1'),
(1,2, NULL, 'test2'),
(1,3, 1.95, 'test3'),
(1,4, 51, 'test4'),
(1,5, 105.75, 'test5'),
(1,6, 0, 'test6'),
(1,7, 173, 'test7'),
(1,8, 256.35, 'test8'),
(2,1, 33158.3, 'test1'),
(2,2, 7925396, 'test2'),
(2,3, 0, 'test3'),
(2,4, NULL, 'test4'),
(2,5, 2461684, 'test5'),
(2,6, 159392, 'test6'),
(2,7, 14791, 'test7'),
(2,8, 14555, 'test8');
I am trying to get a horizontal table like the following (per id and a horizontal structure for Loss and Carrier):
I was trying case when end statements, but I wasn't achieving the desired results.
Can someone please help? I appreciate it.
This has been asked and answered hundreds of times. But it was easier to code a solution than point you to a duplicate. Excellent job posting table structure, sample data and desired output!!!
The easiest solution is using conditional aggregation like this.
select ID
, Loss1 = max(case when RowNum = 1 then Loss end)
, Loss2 = max(case when RowNum = 2 then Loss end)
, Loss3 = max(case when RowNum = 3 then Loss end)
, Loss4 = max(case when RowNum = 4 then Loss end)
, Loss5 = max(case when RowNum = 5 then Loss end)
, Loss6 = max(case when RowNum = 6 then Loss end)
, Loss7 = max(case when RowNum = 7 then Loss end)
, Loss8 = max(case when RowNum = 8 then Loss end)
, Carrier1 = max(case when RowNum = 1 then Carrier end)
, Carrier2 = max(case when RowNum = 2 then Carrier end)
, Carrier3 = max(case when RowNum = 3 then Carrier end)
, Carrier4 = max(case when RowNum = 4 then Carrier end)
, Carrier5 = max(case when RowNum = 5 then Carrier end)
, Carrier6 = max(case when RowNum = 6 then Carrier end)
, Carrier7 = max(case when RowNum = 7 then Carrier end)
, Carrier8 = max(case when RowNum = 8 then Carrier end)
from #mytable
group by ID

How to pivot by two columns into predefined table?

I've seen this question, this and this, however these are not what I want.
Please, do not close my question as it is not duplicate. It is really important to me.
I've managed to pivot a table, but this is not desired result:
The desired result looks like this:
My sample data is(it is just an example as OperatorX and OC columns should be 50 times):
DECLARE #OperatorPrice TABLE (ID INT NOT NULL, OperatorId INT NULL, Price
NUMERIC(18,3) NULL, FName VARCHAR(50) NULL)
INSERT INTO #OperatorPrice (
ID, OperatorId, Price, FName
)
VALUES
(226, 996, 22954,'Operator1')
, (266, 1016, 79011.2, 'Operator3')
, (112, 1029, 14869, 'Operator4')
, (93, 1031, 10568.96, 'Operator5')
DECLARE #TR TABLE
(
ID INT NULL ,
Operator1 DECIMAL(18,3) NULL, OC1 DECIMAL(18,3) NULL, Operator2 DECIMAL(18,3) NULL,
OC2 DECIMAL(18,3) NULL, Operator3 DECIMAL(18,3) NULL, OC3 DECIMAL(18,3) NULL,
Operator4 DECIMAL(18,3) NULL, OC4 DECIMAL(18,3) NULL, Operator5 DECIMAL(18,3) NULL,
OC5 DECIMAL(18,3) NULL
)
Example code:
INSERT #TR
(ID ,
Operator1, OC1, Operator2, OC2, Operator3, OC3, Operator4, OC4,
Operator5, OC5)
SELECT ID ,
Operator1, OC1, Operator2, OC2, Operator3, OC3, Operator4, OC4,
Operator5, OC5
FROM
(SELECT Price, id, FName
FROM #OperatorPrice) AS SourceTable
PIVOT
(
sum(Price)
FOR FName IN (Operator1, OC1, Operator2, OC2, Operator3, OC3,
Operator4, OC4, Operator5, OC5)
) AS PivotTable
SELECT * FROM #TR
How can I insert data into OC columns?
Perhaps something like this.
In your alias SOURCETABLE, we just add a UNION ALL of possible combinations for an ID with NULL values. In this case the MIN(ID) and values 1 - 50
Just be sure to
1) Define #TR with columns Operator1,OC1,..,Operator50,OC50 <<< OC# can be an INT
2) in the FOR Item IN(Operator1,OC1,..,Operator50,OC50)
Example -- Edit Corrected to allow for >9 operators
INSERT #TR
SELECT *
FROM (
Select A.ID
,B.*
From #OperatorPrice A
Cross Apply ( values (FName,Price)
,('OC'+replace(FName,'Operator',''),OperatorID)
) B (Item,Value)
Union All
Select ID=(select min(ID) From #OperatorPrice)
,B.*
From ( Select Top 50 N=Row_Number() Over (Order By (Select NULL)) From master..spt_values n1 ) A
Cross Apply ( values (concat('Operator',N),NULL)
,(concat('OC',N),NULL)
) B (Item,Value)
) AS SourceTable
PIVOT ( sum(Value) FOR Item IN (Operator1, OC1, Operator2, OC2, Operator3, OC3, Operator4, OC4, Operator5, OC5) ) AS PivotTable
Select * from #TR
Returns -- Notice Operator2
Using your sample tables and data this is pretty easy with conditional aggregation. Not really clear though how you determine which operator number is which. Hopefully you have something better than parsing numbers out of the values but who knows.
select op.ID
, Operator1 = max(case when convert(int, replace(FName, 'Operator', '')) = 1 then Price end)
, OC1 = max(case when convert(int, replace(FName, 'Operator', '')) = 1 then OperatorID end)
, Operator2 = max(case when convert(int, replace(FName, 'Operator', '')) = 2 then Price end)
, OC2 = max(case when convert(int, replace(FName, 'Operator', '')) = 2 then OperatorID end)
, Operator3 = max(case when convert(int, replace(FName, 'Operator', '')) = 3 then Price end)
, OC3 = max(case when convert(int, replace(FName, 'Operator', '')) = 3 then OperatorID end)
, Operator4 = max(case when convert(int, replace(FName, 'Operator', '')) = 4 then Price end)
, OC4 = max(case when convert(int, replace(FName, 'Operator', '')) = 4 then OperatorID end)
, Operator5 = max(case when convert(int, replace(FName, 'Operator', '')) = 5 then Price end)
, OC5 = max(case when convert(int, replace(FName, 'Operator', '')) = 5 then OperatorID end)
from #OperatorPrice op
cross apply
(
values
(1)
,(2)
,(3)
,(4)
)x(N)
group by op.ID

SQL query SUM() AND GROUP BY for 2 columns in a table

I am using Microsoft Sql Server management studio.
I have had mixed success creating a tax report for a particular type of invoice that I have.
I have amounts under 6%, other amounts under 13.5% and the last amount has a complete total of both 6% and 13.5%.
I have got my answer in the results, but two different rows for each invoice are displayed. One is for 6% values and the other for 13.5% values.
I need to somehow merge these two rows into one single row for each invoice.
My Sql query is as follows:
SELECT tran_no ,
tran_date ,
( SELECT SUM(edetail_amt)
WHERE edetail_taxid = '6008U_='
) AS '6% amt' ,
( SELECT SUM(edetail_per)
WHERE edetail_taxid = '6008U_='
) AS '6% vat' ,
( SELECT SUM(edetail_amt)
WHERE edetail_taxid = '6008U_>'
) AS '13.5% amt' ,
( SELECT SUM(edetail_per)
WHERE edetail_taxid = '6008U_>'
) AS '13.5% vat' ,
( SELECT SUM(edetail_amt + edetail_per)
WHERE edetail_taxid IN ( '6008U_=', '6008U_>' )
) AS 'Net Total'
FROM h_edetail
INNER JOIN h_tran ON edetail_tranid = tran_kid
WHERE tran_trantype = 'PI'
AND tran_date = '2016-11-03 00:00:00.000'
GROUP BY tran_no ,
tran_date ,
edetail_taxid
ORDER BY tran_no;
A screenshot of the query along with the results are as follows:
If am not wrong you are looking for this
SELECT tran_no,
tran_date,
Sum(case when edetail_taxid = '6008U_=' then edetail_amt else 0 end) AS '6% amt',
Sum(case when edetail_taxid = '6008U_=' then edetail_per else 0 end) AS '6% vat',
Sum(case when edetail_taxid = '6008U_>' then edetail_amt else 0 end) AS '13.5% amt',
Sum(case when edetail_taxid = '6008U_>' then edetail_per else 0 end) AS '13.5% vat',
Sum(case when edetail_taxid IN ( '6008U_=', '6008U_>' ) then edetail_amt + edetail_per else 0 end) AS 'Net Total'
FROM h_edetail
INNER JOIN h_tran
ON edetail_tranid = tran_kid
WHERE tran_trantype = 'PI'
AND tran_date = '2016-11-03 00:00:00.000'
GROUP BY tran_no,
tran_date
ORDER BY tran_no
Because of select sum(edetail_amt) where edetail_taxid='6008U_=' you are forced to add edetail_taxid in group by that is the reason for duplicate records. You can do that by adding case inside SUM aggregate

How to Display data with 'yes' or 'no' entries unique.

This is my data
unitCode stunum assNo subStatus
SIT111 1000 1 Yes
SIT111 1000 2 No
SIT111 3000 1 No
How do i generate only results with ONLY a 'No'
eg: Only student 3000 should come up. Since that person has not handed in ANY assignments. ?
You can use the following statement:
select
*
from
(
select
unitCode,
stunum,
sum(case when subStatus = 'Yes' then 1 else 0 end) as CountYes,
sum(case when subStatus = 'No' then 1 else 0 end) as CountNo
from
students
group by
unitCode, stunum
) as student
inner join student_details
on student.stunum = student_details.stunum
where
CountNo > 0 and CountYes = 0;
declare #T table
(
unitCode varchar(10),
stunum int,
assNo int,
subStatus varchar(3)
)
insert into #T values
('SIT111', 1000, 1, 'Yes'),
('SIT111', 1000, 2, 'No'),
('SIT111', 3000, 1, 'No')
select *
from #T as T
where T.subStatus = 'No' and
T.stunum not in (select stunum
from #T
where subStatus = 'Yes')

Resources