SQL Server Drop NULLS in pivot - sql

I have a base table. Base table
I want to put in linear form that is why I use pivot to have it. And my query goes like:
select
[report_date] AS 'Date'
,[30],[percent_30] AS '%30'
,[45],[percent_45] AS '%45'
,[60],[percent_60] AS '%60'
,[75],[percent_75] AS '%75'
,[90],[percent_90] AS '%90'
,[105],[percent_105] AS '%105'
,[120],[percent_120] AS '%120'
,[TOTAL] AS 'Total Sales'
--,[total_percentage] AS 'Total Percent'
from database.dbo.delivery_report_logs
PIVOT(SUM(Sale_Count)
FOR description IN ([30],[45],[60],[75],[90],[105],[120],[TOTAL])) AS pvz
But the result looks like this.
I want to remove all nulls. Any help? Thank you.
Here is my expected output:
Sample Output

select
[report_date] AS 'Date'
,[30],[percent_30] AS '%30'
,[45],[percent_45] AS '%45'
,[60],[percent_60] AS '%60'
,[75],[percent_75] AS '%75'
,[90],[percent_90] AS '%90'
,[105],[percent_105] AS '%105'
,[120],[percent_120] AS '%120'
,[TOTAL] AS 'Total Sales'
--,[total_percentage] AS 'Total Percent'
from database.dbo.delivery_report_logs
PIVOT ISNULL(SUM(Sale_Count),0)
FOR description IN ([30],[45],[60],[75],[90],[105],[120],[TOTAL])) AS pvz

This is solved. I use temporary table to pivot the data and insert it to a log table and it gives me the result I need.

you can also use a query like this that uses and aggregate with a case expression
SELECT report_date,
SUM(CASE WHEN Description = '30' THEN sale_count END) AS [30],
SUM(CASE WHEN Description = '30' THEN percent_30 END) AS [percent_30],
SUM(CASE WHEN Description = '45' THEN sale_count END) AS [30],
SUM(CASE WHEN Description = '45' THEN percent_45 END) AS [percent_45],
SUM(CASE WHEN Description = '60' THEN sale_count END) AS [30],
SUM(CASE WHEN Description = '60' THEN percent_60 END) AS [percent_60],
SUM(CASE WHEN Description = '75' THEN sale_count END) AS [30],
SUM(CASE WHEN Description = '75' THEN percent_70 END) AS [percent_70],
SUM(CASE WHEN Description = '90' THEN sale_count END) AS [30],
SUM(CASE WHEN Description = '90' THEN percent_90 END) AS [percent_90],
SUM(CASE WHEN Description = '105' THEN sale_count END) AS [30],
SUM(CASE WHEN Description = '105' THEN percent_105 END) AS [percent_105],
SUM(CASE WHEN Description = '120' THEN sale_count END) AS [30],
SUM(CASE WHEN Description = '120' THEN percent_120 END) AS [percent_120],
SUM(CASE WHEN Description = 'TOTAL' THEN sale_count END) AS [30],
SUM(CASE WHEN Description = 'TOTAL' THEN total_percentage END) AS [total_percentage]
FROM database.dbo.delivery_report_logs
GROUP BY report_date
you can also use MAX or MIN in place of SUM if there is only one value per report_date/percentate

Related

How to use group by function in oracle

Below is the my base table
I need to create view like below format based on my base table.
Here Deposit_Acc_Count is combination of (Type -> SB,RD, FD) and Loan_Acc_Count is (Type ->LO) same as for amount.
Can anyone help me to achieve this.
You can use conditional aggregation while grouping by br_code and cif columns such as
SELECT br_code, cif,
COUNT(CASE WHEN type IN ('SB','RD', 'FD') THEN Amt END) AS deposit_acc_count,
SUM(CASE WHEN type IN ('SB','RD', 'FD') THEN Amt ELSE 0 END) AS deposit_acc_amt,
COUNT(CASE WHEN type = 'LO' THEN Amt END) AS loan_acc_count,
SUM(CASE WHEN type = 'LO' THEN Amt ELSE 0 END) AS loan_acc_amt,
COUNT(*) AS total_count,
SUM(amt) AS total_amt
FROM t
GROUP BY br_code, cif
Demo

Combine Table in SQL

I have two tables would like to combine.
I would like the table will automatically add a row for image2 when there are new generalname in image1.
select B.Trsdate, count(B.Billno) As Billno, sum(B.pax) As Pax, sum(B.Grossamount) As GrossAmount, sum(B.discountamount) As Discount, sum(B.taxamount) As Tax, sum(B.servicechargeamount) As SCharge, sum(B.nettamount) As NettAmt, sum(B.rounddiff) As RDiff, sum(B.roundamt) As RoundAmt, sum(B.reversalYN) As RevBillNo, SUM(GD.CASH) AS 'P_CASH', SUM(GD.VISA) AS 'P_VISA', SUM(GD.MASTER) AS 'P_MASTER', SUM(GD.AMEX) AS 'P_Amex', SUM(GD.CityLedger) AS 'P_CityLedger', SUM(GD.OtherPayment) As 'P_Other'
from vpos_eod_bills As B
INNER JOIN
(
SELECT TrsNo,SUM(CASH) as CASH,SUM(Visa) as Visa, SUM(Master) as Master, SUM(Amex) AS Amex, SUM(CityLedger) as CityLedger, SUM(OtherPayment) as OtherPayment, SUM(Total) as Total FROM
(
select TrsNo, GENERALNAME,
(case WHEN(Generalname IN ('CASH'))
THEN
SUM(AMOUNT)
ELSE
0
END) as 'CASH',
(case WHEN(Generalname IN ('VISA'))
THEN
SUM(AMOUNT)
ELSE
0
END) as 'Visa',
(case WHEN(Generalname IN ('MASTER'))
THEN
SUM(AMOUNT)
ELSE
0
END) as 'Master',
(case WHEN(Generalname IN ('AMEX'))
THEN
SUM(AMOUNT)
ELSE
0
END) as 'Amex',
(case WHEN(Generalname = 'City Ledger' OR Generalname = 'CREDIT A/C' OR Generalname = 'BOSS' OR Generalname = 'ENTERTAINMENT')
THEN
SUM(AMOUNT)
ELSE
0
END) as 'CityLedger',
(case WHEN(Generalname not IN ('CASH','Voucher','VISA','MASTER','AMEX','JCB','City Ledger','CREDIT A/C','BOSS','ENTERTAINMENT') and (Generalname not like '%card%') and (Generalname not like '%Coupon%') and (Generalname not like '%GROUPON%') and (Generalname not like '%COURSE%'))
THEN
SUM(AMOUNT)
ELSE
0
END) as 'OtherPayment',
SUM(AMOUNT) as Total
from Vpos_eod_GeneralDetails
where BillType = 'P'
group by TrsNo, GeneralName
) As A
Group By A.trsno
)As GD ON GD.TrsNo = B.TrsNo
where B.PaidStatus = '1' and B.VoidStatus = '0' and (B.trsdate between '20200101' and '20200131')
group by B.trsdate

Oracle SQL - simplifying the totals column

I have the below issues that I would like to address:
Is there a way to simplify the Total column?
The bottom row reads as null, I would like that to be "Total" as well.
Is it better to ROLLUP the way I have it, ROLLUP((status))? Or this is exactly same as ROLLUP(status)?
Below is my query:
SELECT
status AS "ROW LABELS",
COUNT(case when source = 'INTERNET' THEN 1 end) AS "INTERNET",
COUNT(case when source = 'SALES' THEN 1 end) AS "SALES",
COUNT(case when source = 'REP' THEN 1 end) AS "REP",
COUNT(case when source = 'COM' THEN 1 end) AS "COM",
(COUNT(case when source = 'INTERNET' THEN 1 end) +
COUNT(case when source = 'SALES' THEN 1 end) +
COUNT(case when source = 'REP' THEN 1 end) +
COUNT(case when source = 'COM' THEN 1 end)
) AS Total
FROM
SOMETABLE
GROUP BY ROLLUP((status))
order by 1;
Below is my data:
If by "simplify" you mean "make the calculation more succinct", then yes. The following will work:
COUNT(CASE WHEN source IN ('INTERNET', 'SALES', 'REP', 'COM') THEN 1 END)
Simply use nvl to convert the NULL to a value: NVL(status, 'TOTAL') AS row_labels
ROLLUP( (status) ) is the same as ROLLUP( status )

ORDER BY Alias not working

UPDATING QUESTION:
ERROR: column "Fruits" does not exist
Running Postgres 7.4(Yeah we are upgrading)
Why can't I ORDER BY the column alias? wants tof."TypeOfFruits" in the ORDER BY as well, why?
SELECT (CASE
WHEN tof."TypeOfFruits" = 'A' THEN 'Apple'
WHEN tof."TypeOfFruits" = 'P' THEN 'Pear'
WHEN tof."TypeOfFruits" = 'G' THEN 'Grapes'
ELSE 'Other' END) AS "Fruits",
SUM(CASE WHEN r.order_date
BETWEEN DATE_TRUNC('DAY', LOCALTIMESTAMP) AND DATE_TRUNC('DAY', LOCALTIMESTAMP) + INTERVAL '1 DAY'
THEN 1 ELSE 0 END) AS daily,
SUM(CASE WHEN r.order_date
BETWEEN DATE_TRUNC('MONTH', LOCALTIMESTAMP) AND DATE_TRUNC('MONTH', LOCALTIMESTAMP) + INTERVAL '1 MONTH'
THEN 1 ELSE 0 END) AS monthly,
SUM(CASE WHEN r.order_date
BETWEEN DATE_TRUNC('YEAR', LOCALTIMESTAMP) AND DATE_TRUNC('YEAR', LOCALTIMESTAMP) + INTERVAL '1 YEAR'
THEN 1 ELSE 0 END) AS yearly,
SUM(CASE WHEN r.order_date >= '01-01-2011 00:00:00' THEN 1 ELSE 0 END) AS lifetime
FROM reports AS r, "TypeOfFruits" AS tof
WHERE r.id = tof."ID"
GROUP BY "Fruits"
ORDER BY CASE
WHEN "Fruits" = 'Apple' THEN 1
WHEN "Fruits" = 'Pear' THEN 2
WHEN "Fruits" = 'Grapes' THEN 3
ELSE 4
END
Results as of now
Fruits;daily;monthly;yearly;lifetime
"Apple";17;1174;3136;3136
"Pear";28;94;94;94
"Grapes";0;191;490;490
"Other";0;2;27;27
"Other";0;0;1;1
"Other";0;0;27;27
"Other";0;6;28;28
"Other";0;58;229;229
"Other";0;3;3;3
"Other";0;0;1;1
Desired results would be one row with the "Other" total, so four rows altogether
(x would be the total)
Fruits;daily;monthly;yearly;lifetime
"Apple";17;1174;3136;3136
"Pear";28;94;94;94
"Grapes";0;191;490;490
"Other";x;x;x;x
You can use ORDER BY 1 to order by the first field, which is "Fruits". The same is valid for GROUP BY
Update
For the order, instead of doing the case in the order by, create a new column in.. say.. the second position:
(CASE
WHEN "Fruits" = 'Apple' THEN 1
WHEN "Fruits" = 'Pear' THEN 2
WHEN "Fruits" = 'Grapes' THEN 3
ELSE 4 ) as Order
Then in you ORDER BY 2.
The reason for this can be found in the documentation:
Each expression [in the ORDER BY list] can be the name or ordinal number of an output column (SELECT list item), or it can be an arbitrary expression formed from input-column values.
(my emphasis)
The reason for this is that old versions of the SQL standard (SQL-92) only allowed sorting by output column name or number, whereas newer versions allow sorting by arbitrary expressions, but those expressions are formed from input column values.
Other answers already contain various suitable workarounds for your case.
The alias is assigned after the order by so you can't use it in the order by. Use this instead:
(CASE
WHEN tof."TypeOfFruits" = 'A' THEN 'Apple'
WHEN tof."TypeOfFruits" = 'P' THEN 'Pear'
WHEN tof."TypeOfFruits" = 'G' THEN 'Grapes'
ELSE 'Other' END)
Consider something like this:
SELECT * FROM (SELECT (CASE
WHEN tof."TypeOfFruits" = 'A' THEN 'Apple'
WHEN tof."TypeOfFruits" = 'P' THEN 'Pear'
WHEN tof."TypeOfFruits" = 'G' THEN 'Grapes'
ELSE 'Other' END) AS "Fruits",
(CASE
WHEN tof."TypeOfFruits" = 'A' THEN 1
WHEN tof."TypeOfFruits" = 'P' THEN 2
WHEN tof."TypeOfFruits" = 'G' THEN 3
ELSE 4 END) as NUM
FROM ..... <rest of your query without group by and order by .....
)
GROUP BY Fruits
ORDER BY NUM
You could try something like this ... untested, but I've seen similar queries.
Let me know if it works...
SELECT "Fruits",
SUM(CASE WHEN r.order_date
BETWEEN DATE_TRUNC('DAY', LOCALTIMESTAMP) AND DATE_TRUNC('DAY', LOCALTIMESTAMP) + INTERVAL '1 DAY'
THEN 1 ELSE 0 END) AS daily,
SUM(CASE WHEN r.order_date
BETWEEN DATE_TRUNC('MONTH', LOCALTIMESTAMP) AND DATE_TRUNC('MONTH', LOCALTIMESTAMP) + INTERVAL '1 MONTH'
THEN 1 ELSE 0 END) AS monthly,
SUM(CASE WHEN r.order_date
BETWEEN DATE_TRUNC('YEAR', LOCALTIMESTAMP) AND DATE_TRUNC('YEAR', LOCALTIMESTAMP) + INTERVAL '1 YEAR'
THEN 1 ELSE 0 END) AS yearly,
SUM(CASE WHEN r.order_date >= '01-01-2011 00:00:00' THEN 1 ELSE 0 END) AS lifetime
FROM reports AS r
,(SELECT "ID",
CASE
WHEN tof."TypeOfFruits" = 'A' THEN 'Apple'
WHEN tof."TypeOfFruits" = 'P' THEN 'Pear'
WHEN tof."TypeOfFruits" = 'G' THEN 'Grapes'
ELSE 'Other'
END AS "Fruits" FROM "TypeOfFruits" ) AS "tof"
WHERE r.id = tof."ID"
GROUP BY "Fruits"
ORDER BY CASE
WHEN "Fruits" = 'Apple' THEN 1
WHEN "Fruits" = 'Pear' THEN 2
WHEN "Fruits" = 'Grapes' THEN 3
ELSE 4
END
Try using backticks (`) instead of single/double quotes to wrap your alias name.
Had the same issue with MySQL; backticks fixed the problem.

SQL Query to Calculate two Amounts on the same row

probably a very simple answer but i'm new to T-SQL so could do with some help!
I need a 3rd column that works out TotInc - (minus) TotEx to give me a TotalDisposableIncome
Here is my SQL:
--This gives me the Total Income and Total Expenditure on the same row
SELECT
SUM(CASE WHEN Type = '1' THEN Amount ELSE 0 END) as TotalInc,
SUM(CASE WHEN Type = '2' THEN Amount ELSE 0 END) as TotEx
FROM ClaimFinancials
Thanks!
You could use a Common Table Expression (CTE):
WITH T1 AS
(
SELECT
SUM(CASE WHEN Type = '1' THEN Amount ELSE 0 END) as TotalInc,
SUM(CASE WHEN Type = '2' THEN Amount ELSE 0 END) as TotEx
FROM ClaimFinancials
)
SELECT TotalInc, TotEx, TotalInc - TotEx AS TotalDisposableIncome
FROM T1
Or an ordinary subquery:
SELECT TotalInc, TotEx, TotalInc - TotEx AS TotalDisposableIncome
FROM
(
SELECT
SUM(CASE WHEN Type = '1' THEN Amount ELSE 0 END) as TotalInc,
SUM(CASE WHEN Type = '2' THEN Amount ELSE 0 END) as TotEx
FROM ClaimFinancials
) T1
You can't reference your column aliases elsewhere in your SELECT clause. Here is one alternative.
SELECT TotalInc, TotEx, TotInc - TotEx as TotalDisposable
FROM (
SELECT
SUM(CASE WHEN Type = '1' THEN Amount ELSE 0 END) as TotalInc,
SUM(CASE WHEN Type = '2' THEN Amount ELSE 0 END) as TotEx
FROM ClaimFinancials
) AS Total
There's more than one way to do it.
WITH T1 AS
(
SELECT
Type,
SUM(Amount as Total
FROM ClaimFinancials
)
SELECT
Inc.Total as TotalInc,
Ex.Total as TotEx,
Inc.Total - Ex.Total AS TotalDisposableIncome
FROM T1 Inc, T2 Ex
where T1.Type = 1 and T2.Type = 2
SELECT
SUM(CASE WHEN Type = '1' THEN Amount ELSE 0 END) as TotalInc,
SUM(CASE WHEN Type = '2' THEN Amount ELSE 0 END) as TotEx,
SUM(CASE
WHEN Type = '1' THEN Amount
WHEN Type = '2' Then -Amount
ELSE 0
END) AS TotalDisposableIncome
FROM ClaimFinancials