Display Column Value in Case When in SQL - sql

need help for below.
Table1
+------------+-------------------+----------+
| Shipmnt | Costtype | cost |
+------------+-------------------+----------+
|22 | toll | 100 |
|23 | parking | 111 |
|25 | tax | 25 |
+------------+-------------------+----------+
Expected Result
+----------+--------+-----------+-------+
| shipmnt | toll | parking | tax |
+----------+--------+-----------+-------+
| 22 | 100 | 0 | 0 |
| 23 | 0 | 111 | 0 |
| 25 | 0 | 0 | 25 |
+----------+--------+-----------+-------+
i m trying to use case when but not able to get column.

You didn't state your DBMS, the following is standard SQL and works on all DBMS I know of.
select shipmt,
sum(case when costtype = 'toll' then cost end) as toll_costs,
sum(case when costtype = 'parking' then cost end) as parking_costs,
sum(case when costtype = 'tax' then cost end) as tax_costs
from shipments
group by shipmt;

Select distinct a.shipment,
ISNULL((Select cost from Table1 where Costtype='troll' and shipmnt=a.shipmnt),0) as troll,
ISNULL((Select cost from Table1 where Costtype='parking' and shipmnt=a.shipmnt),0) as parking,
ISNULL((Select cost from Table1 where Costtype='tax' and shipmnt=a.shipmnt),0) as tax
from Table1 a

QUERY
SELECT shipmnt,
MAX(IF(costType='toll',cost,0)) AS toll,
MAX(IF(costType='parking',cost,0)) AS parking,
MAX(IF(costType='tax',cost,0)) AS tax
FROM tbl1
GROUP BY shipmnt;
FIND FIDDLE HERE

Related

MySql select two queries in one statement

I have bank transaction data to select two functions in a single query.
I have data like this
|ID | name | amount |
|----|--------|--------|
| 1 | xxx | 1000 |
| 2 | yyy | -500 |
| 3 | qqq | 1500 |
| 4 | ggg | -1000 |
------------------------
I want like this
-------------------------------------------
|ID | name | amount | sell | buy | cum |
|----|--------|--------|------|-----|-----|
| 1 | xxx | 1000 | 1000 | n/a |1000 |
| 2 | yyy | -500 | n/a |-500 | 500 |
| 3 | qqq | 1500 | 1500 | n/a | 2000|
| 4 | ggg | -1000 | n/A |-1000| 1000|
------------------------------------------
My code is.
SELECT ID, name, amount,
CASE WHEN amount >=0 THEN amount END AS sell,
CASE WHEN amount <=0 THEN amount END AS buy,
From bank
Join (select #csum := #csum + amount as csum from bank
Join (select #csum := 0) r order by ID);
Ther no need for multiple select statement.
SELECT ID, name, amount,
CASE WHEN amount >=0 THEN amount END AS sell,
CASE WHEN amount <=0 THEN amount END AS buy,
#csum := #csum + amount as csum from bank
Join (select #csum := 0) r order by ID);
The correct way to write this query uses window functions:
SELECT ID, name, amount,
(CASE WHEN amount >= 0 THEN amount END) AS sell,
(CASE WHEN amount <= 0 THEN amount END) AS buy,
SUM(AMOUNT) OVER (ORDER BY id) as cumulative
FROM bank;

Duplicate records upon joining table

I am still very new to SQL and Tableau however I am trying to work myself towards achieving a personal project of mine.
Table A; shows a table which contains the defect quantity per product category and when it was raised
+--------+-------------+--------------+-----------------+
| Issue# | Date_Raised | Category_ID# | Defect_Quantity |
+--------+-------------+--------------+-----------------+
| PCR12 | 11-Jan-2019 | Product#1 | 14 |
| PCR13 | 12-Jan-2019 | Product#1 | 54 |
| PCR14 | 5-Feb-2019 | Product#1 | 5 |
| PCR15 | 5-Feb-2019 | Product#2 | 7 |
| PCR16 | 20-Mar-2019 | Product#1 | 76 |
| PCR17 | 22-Mar-2019 | Product#2 | 5 |
| PCR18 | 25-Mar-2019 | Product#1 | 89 |
+--------+-------------+--------------+-----------------+
Table B; shows the consumption quantity of each product by month
+-------------+--------------+-------------------+
| Date_Raised | Category_ID# | Consumed_Quantity |
+-------------+--------------+-------------------+
| 5-Jan-2019 | Product#1 | 100 |
| 17-Jan-2019 | Product#1 | 200 |
| 5-Feb-2019 | Product#1 | 100 |
| 8-Feb-2019 | Product#2 | 50 |
| 10-Mar-2019 | Product#1 | 100 |
| 12-Mar-2019 | Product#2 | 50 |
+-------------+--------------+-------------------+
END RESULT
I would like to create a table/bar chart in tableau that shows that Defect_Quantity/Consumed_Quantity per month, per Category_ID#, so something like this below;
+----------+-----------+-----------+
| Month | Product#1 | Product#2 |
+----------+-----------+-----------+
| Jan-2019 | 23% | |
| Feb-2019 | 5% | 14% |
| Mar-2019 | 89% | 10% |
+----------+-----------+-----------+
WHAT I HAVE TRIED SO FAR
Unfortunately i have not really done anything, i am struggling to understand how do i get rid of the duplicates upon joining the tables based on Category_ID#.
Appreciate all the help I can receive here.
I can think of doing left joins on both product1 and 2.
select to_char(to_date(Date_Raised,'d-mon-yyyy'),'mon-yyyy')
, (p2.product1 - sum(case when category_id='Product#1' then Defect_Quantity else 0 end))/p2.product1 * 100
, (p2.product2 - sum(case when category_id='Product#2' then Defect_Quantity else 0 end))/p2.product2 * 100
from tableA t1
left join
(select to_char(to_date(Date_Raised,'d-mon-yyyy'),'mon-yyyy') Date_Raised
, sum(Comsumed_Quantity) as product1 tableB
where category_id = 'Product#1'
group by to_char(to_date(Date_Raised,'d-mon-yyyy'),'mon-yyyy')) p1
on p1.Date_Raised = t1.Date_Raised
left join
(select to_char(to_date(Date_Raised,'d-mon-yyyy'),'mon-yyyy') Date_Raised
, sum(Comsumed_Quantity) as product2 tableB
where category_id = 'Product#2'
group by to_char(to_date(Date_Raised,'d-mon-yyyy'),'mon-yyyy')) p2
on p2.Date_Raised = t1.Date_Raised
group by to_char(to_date(Date_Raised,'d-mon-yyyy'),'mon-yyyy')
By using ROW_NUMBER() OVER (PARTITION BY ORDER BY ) as RN, you can remove duplicate rows. As of your end result you should extract month from date and use pivot to achieve.
I would do this as:
select to_char(date_raised, 'YYYY-MM'),
(sum(case when product = 'Product#1' then defect_quantity end) /
sum(case when product = 'Product#1' then consumed_quantity end)
) as product1,
(sum(case when product = 'Product#2' then defect_quantity end) /
sum(case when product = 'Product#2' then consumed_quantity end)
) as product2
from ((select date_raised, product, defect_quantity, 0 as consumed_quantity
from a
) union all
(select date_raised, product, 0 as defect_quantity, consumed_quantity
from b
)
) ab
group by to_char(date_raised, 'YYYY-MM')
order by min(date_raised);
(I changed the date format because I much prefer YYYY-MM, but that is irrelevant to the logic.)
Why do I prefer this method? This will include all months where there is a row in either table. I don't have to worry that some months are inadvertently filtered out, because there are missing production or defects in one month.

SQL ratio between rows

I have a SQL table with the following format:
+------------------------------------+
| function_id | event_type | counter |
+-------------+------------+---------+
| 1 | fail | 1000 |
| 1 | started | 5000 |
| 2 | fail | 800 |
| 2 | started | 4500 |
| ... | ... | ... |
+-------------+------------+---------+
I want to run a query over this that will group the results by function_id, by giving a ratio of the number of 'fail' events vs the number of 'started' events, as well as maintaining the number of failures. I.e. I want to run a query that will give something that looks like the following:
+-------------------------------------+
| function_id | fail_ratio | failures |
+-------------+------------+----------+
| 1 | 20% | 1000 |
| 2 | 17.78% | 800 |
| ... | ... | |
+-------------+------------+----------+
I've tried a few approaches but have been unsuccessful so far. I'm using Apache Drill SQL at the moment, as this data is being pulled from flat files.
Any help would be greatly appreciated! :)
This is all conditional aggregation:
select function_id,
sum(case when event_type = 'fail' then counter*1.0 end) / sum(case when event_type = 'started' then counter end) as fail_start_ratio,
sum(case when event_type = 'fail' then counter end) as failures
from t
group by function_id

Getting totals and sub-totals in Parent-Child hierarchy

I have the following table structures for which I am trying to obtain a totals and subtotals and show a rollup of the values.
ChartOfAccounts(AccountNumber, AccountDescription, ParentAccountNumber, IsControlAccount)
Ledger(LedgerId, JournalId, AccountNumber, IsDebit, Amount)
I have managed to use CTE to obtain the required Parent-Child relationships but am unsure how to use this get control account balances which rollup into parent accounts.
So far, I have managed to put the following query together which is not entirely what I want --> SQL Fiddle. The current query does not seem to rollup and group the parent-child totals correctly. (I have excluded the year,month columns from the fiddle)
Another way to describe the problem, would be to say that all control accounts should have the total of it's child accounts.
My required output is the following
(year, month, AccountNumber, AccountDescription, DebitBalance, CreditBalance, Balance)
|Account#|Acc Desc | DR | CR | BAL |
|1000 |Accounts Receivable |10000 |5000 |5000 |
|1200 |Buyer Receivables |5000 |0 |5000 |
|12001 |Buyer Receivables - Best Buy |5000 |0 |5000 |
|1500 |Offers |5000 |5000 |0 |
|4000 |Accounts Payable | |4475.06 |4475.06 |
|4100 |Supplier Invoice Payables | |4475.06 |4475.06 |
|41002 |Supplier Invoice Payables - Knechtel | |4475.06 |4475.06 |
|6000 |Revenue | |524.93 |524.93 |
|6100 |Membership Fees Revenue | | |0 |
|6200 |Processing Fees Revenue | |100 |100 |
|62002 |Processing Fees Revenue - Knechtel | |100 |100 |
|6300 |Fees Revenue | |424.93 |424.93 |
|63002 |Fees Revenue - Knechtel | |424.93 |424.93 |
Here is what I came up with and was able to get really close to matching your desired output
WITH CTEAcc
AS
(
SELECT
coa.accountDescription,coa.accountnumber,coa.accountnumber as parentaccount
FROM ChartOfAccounts coa
where iscontrolaccount=1
union all select c.accountdescription, coa.accountnumber, c.ParentAccount
from chartofaccounts coa
inner join cteacc c on coa.ParentAccountNumber=c.accountnumber
)
select parentaccount as [Account#], accountdescription as [Acc Desc],
sum(case when isdebit=1 then amount else 0 end) as DR,
sum(case when isdebit=0 then amount else 0 end) as CR,
sum(case when isdebit=1 then amount else 0 end)-sum(case when isdebit=0 then amount else 0 end) as BAL
from (select c.accountdescription, c.accountnumber,
c.parentaccount, l.isdebit, l.amount
from cteacc c
left join ledger l
on c.accountnumber=l.accountnumber
union all select c.accountdescription,
c.accountnumber, c.accountnumber as parentaccount,
l.isdebit, l.amount
from ChartOfAccounts c
inner join ledger l
on c.accountnumber=l.accountnumber where amount<>0) f
group by parentaccount, accountdescription
order by parentaccount
Here is the sql fiddle: http://www.sqlfiddle.com/#!3/d94bc/106
Yet another variation. Kept the hierarchy and iscontrol fields in just for reference. First it associates the account hierarchy with each account (the recursive cte). Then, for each account, computes sums of the ledger items for the account based on the hierarchy position (and whether it is a control account or not). Finally, wraps in another query to compute the balance of and strip off unused accounts from the output.
WITH AccountHierarchy AS (
SELECT AccountNumber
,AccountDescription
,CAST(AccountNumber AS VARCHAR(MAX))
+ '/' AS AccountHierarchy
,IsControlAccount
FROM ChartOfAccounts
WHERE ParentAccountNumber IS NULL
UNION ALL
SELECT c.AccountNumber
,c.AccountDescription
,CAST(h.AccountHierarchy AS VARCHAR(MAX))
+ CAST(c.AccountNumber AS VARCHAR(MAX))
+ '/' AS AccountHierarchy
,c.IsControlAccount
FROM ChartOfAccounts c
INNER JOIN AccountHierarchy h ON (c.ParentAccountNumber = h.AccountNumber)
WHERE ParentAccountNumber IS NOT NULL
)
SELECT AccountNumber
,AccountDescription
,AccountHierarchy
,IsControlAccount
,DR
,CR
,CASE WHEN (DR IS NULL AND CR IS NULL) THEN NULL
ELSE COALESCE(DR, 0) - COALESCE(CR, 0)
END AS BAL
FROM (SELECT h.AccountNumber
,h.AccountDescription
,h.AccountHierarchy
,h.IsControlAccount
,(SELECT SUM(l.Amount)
FROM Ledger l
INNER JOIN AccountHierarchy hd ON (l.AccountNumber = hd.AccountNumber)
WHERE l.IsDebit = 1
AND ( (h.IsControlAccount = 1 AND hd.AccountHierarchy LIKE h.AccountHierarchy + '%')
OR hd.AccountHierarchy = h.AccountHierarchy)
) AS DR
,(SELECT SUM(l.Amount)
FROM Ledger l
INNER JOIN AccountHierarchy hd ON (l.AccountNumber = hd.AccountNumber)
WHERE l.IsDebit = 0
AND ( (h.IsControlAccount = 1 AND hd.AccountHierarchy LIKE h.AccountHierarchy + '%')
OR hd.AccountHierarchy = h.AccountHierarchy)
) AS CR
FROM AccountHierarchy h
) x
WHERE NOT(CR IS NULL AND DR IS NULL)
ORDER BY AccountHierarchy
I used this question for a hierarchy example.
Output:
| ACCOUNTNUMBER | ACCOUNTDESCRIPTION | ACCOUNTHIERARCHY | ISCONTROLACCOUNT | DR | CR | BAL |
|----------------------|------------------------------------|-----------------------------------------------------------------|------------------|--------|-----------|------------|
| 1000 | Accounts Receivable | 1000 / | 1 | 10000 | 5000 | 5000 |
| 1200 | Buyer Receivables | 1000 /1200 / | 1 | 5000 | (null) | 5000 |
| 12001 | Buyer Receivables - Best Buy | 1000 /1200 /12001 / | 0 | 5000 | (null) | 5000 |
| 1500 | Offers | 1000 /1500 / | 0 | 5000 | 5000 | 0 |
| 4000 | Accounts Payable | 4000 / | 1 | (null) | 4475.0685 | -4475.0685 |
| 4100 | Supplier Payables | 4000 /4100 / | 1 | (null) | 4475.0685 | -4475.0685 |
| 41002 | Supplier Payables - Knechtel | 4000 /4100 /41002 / | 0 | (null) | 4475.0685 | -4475.0685 |
| 6000 | Revenue | 6000 / | 1 | (null) | 524.9315 | -524.9315 |
| 6200 | Processing Fees Revenue | 6000 /6200 / | 1 | (null) | 100 | -100 |
| 62002 | Processing Fees Revenue - Knechtel | 6000 /6200 /62002 / | 0 | (null) | 100 | -100 |
| 6300 | Fees Revenue | 6000 /6300 / | 1 | (null) | 424.9315 | -424.9315 |
| 63002 | Fees Revenue - Knechtel | 6000 /6300 /63002 / | 0 | (null) | 424.9315 | -424.9315 |
Starting with your desired output I came up with the following query that groups child accounts based on the ParentAccountNumber. The subquery is only needed since I assumed you want to convert any NULL value to 0 before summing up (in SQL, NULL + 42 = NULL).
with preresult as
(
select acc.ParentAccountNumber as AccountNumber,
acc.AccountDescription as "Acc Desc",
ISNULL(ld.Amount, 0) as DR,
ISNULL(lc.Amount, 0) as CR
from ChartOfAccounts acc
left outer join Ledger ld
on (ld.AccountNumber = acc.AccountNumber AND ld.IsDebit = 1)
left outer join Ledger lc
on (lc.AccountNumber = acc.AccountNumber AND lc.IsDebit = 0)
where acc.ParentAccountNumber is not null
)
select c.AccountNumber as "ACC",
c.AccountDescription as "ACC DESC",
sum(DR) as DR,
sum(CR) as CR,
sum(DR) - sum(CR) AS BL
from preresult p
join ChartOfAccounts c on (c.AccountNumber = p.AccountNumber)
group by c.AccountNumber, c.AccountDescription;
The sqlfiddle can be found here: http://www.sqlfiddle.com/#!3/d94bc/81/0
This seems to give you what you want:
;WITH recurs
AS
(
SELECT C.AccountNumber, C.IsControlAccount, C.ParentAccountNumber, C.AccountDescription,
COALESCE((SELECT SUM(Amount) FROM Ledger WHERE AccountNumber = C.AccountNumber and IsDebit = 1), 0) AS DR,
COALESCE((SELECT SUM(Amount) FROM Ledger WHERE AccountNumber = C.AccountNumber and IsDebit = 0), 0) AS CR,
COALESCE((SELECT SUM(CASE WHEN IsDebit = 0 THEN Amount * -1 ELSE Amount END) FROM Ledger WHERE AccountNumber = C.AccountNumber), 0) AS BAL
FROM ChartOfAccounts C
WHERE IsControlAccount = 0
UNION ALL
SELECT C.AccountNumber, C.IsControlAccount, C.ParentAccountNumber, C.AccountDescription,
r.DR, r.CR, R.BAL
FROM ChartOfAccounts C
INNER JOIN recurs r
ON r.ParentAccountNumber = c.AccountNumber
)
SELECT R.AccountNumber, R.AccountDescription, SUM(R.DR) AS DR, SUM(R.CR) AS CR, SUM(R.BAL) AS BAL
FROM recurs R
WHERE NOT (R.DR = 0 AND R.CR = 0 AND R.BAL = 0)
GROUP BY R.AccountNumber, R.AccountDescription
ORDER BY AccountNumber
SQL Fiddle here
Results:
| ACCOUNTNUMBER | ACCOUNTDESCRIPTION | DR | CR | BAL |
|----------------------|------------------------------------|-------|-----------|------------|
| 1000 | Accounts Receivable | 10000 | 5000 | 5000 |
| 1200 | Buyer Receivables | 5000 | 0 | 5000 |
| 12001 | Buyer Receivables - Best Buy | 5000 | 0 | 5000 |
| 1500 | Offers | 5000 | 5000 | 0 |
| 4000 | Accounts Payable | 0 | 4475.0685 | -4475.0685 |
| 4100 | Supplier Payables | 0 | 4475.0685 | -4475.0685 |
| 41002 | Supplier Payables - Knechtel | 0 | 4475.0685 | -4475.0685 |
| 6000 | Revenue | 0 | 524.9315 | -524.9315 |
| 6200 | Processing Fees Revenue | 0 | 100 | -100 |
| 62002 | Processing Fees Revenue - Knechtel | 0 | 100 | -100 |
| 6300 | Fees Revenue | 0 | 424.9315 | -424.9315 |
| 63002 | Fees Revenue - Knechtel | 0 | 424.9315 | -424.9315 |

Cannot merge Income table and Outcome table with full outer join

I have 2 tables: Income (InvoiceDate, TotalAmount) and Outcome (ExpenseDate, TotalAmount).
Suppose that I have data for each column as below:
Income:
| INVOICEDATE | TOTALAMOUNT |
|-------------|-------------|
| 2013-10-16 | 22000 |
| 2013-10-17 | 14400 |
| 2013-10-18 | 4488 |
Outcome:
| EXPENSEDATE | TOTALAMOUNT |
|-------------|-------------|
| 2013-10-25 | 15 |
I want to merge these 2 tables to show as below:
| DATE | INCOME | OUTCOME |
|------------|--------|---------|
| 2013-10-25 | 0 | 15 |
| 2013-10-16 | 22000 | 0 |
| 2013-10-17 | 14400 | 0 |
| 2013-10-18 | 4488 | 0 |
However when I run my T-SQL, It will show like this instead:
| DATE | INCOME | OUTCOME |
|------------|--------|---------|
| (null) | (null) | 15 |
| 2013-10-16 | 22000 | (null) |
| 2013-10-17 | 14400 | (null) |
| 2013-10-18 | 4488 | (null) |
This is my T-SQL:
SELECT
CASE (income.InvoiceDate)
WHEN NULL THEN Outcome.expenseDate
ELSE income.InvoiceDate
END AS [Date],
CASE (income.TotalAmount)
WHEN NULL THEN 0
ELSE income.TotalAmount
END AS Income,
CASE (Outcome.TotalAmount)
WHEN NULL THEN 0
ELSE Outcome.TotalAmount
END AS Outcome
FROM
Outcome
FULL OUTER JOIN
income ON Outcome.expenseDate = income.InvoiceDate
WHERE
NOT (
Outcome.TotalAmount = 0
AND income.TotalAmount = 0
)
You can test this SQL at http://sqlfiddle.com/#!6/3589f/1
Does anyone know what's wrong with my T-SQL?
Thank You!
Pengan
A CASE statement is a shorthand for a series of = operators. However, NULL is never equal to any value (that's what the IS operator is for), so using CASE to evaluate NULLs is somewhat pointless.
Instead, you can yse the COALESCE function to replace your NULLs with 0s as following:
SELECT Outcome.expenseDate AS [Date],
COALESCE(Income.TotalAMount, 0) AS Income,
COALESCE(Outcome.TotalAMount, 0) AS Outcome
FROM Outcome
FULL OUTER JOIN income ON Outcome.expenseDate = income.InvoiceDate
WHERE NOT (
Outcome.TotalAmount = 0
AND income.TotalAmount = 0
)
You may want a union instead
select InvoiceDate as Date, TotalAmount as Income, 0 as Outcome from Income
union all
select ExpenseDate, 0, TotalAmount from Outcome
If you can have income and expenses on the same date, you can group them from this.
select [date], Sum(Income), Sum(outcome) from
(
select InvoiceDate as Date, TotalAmount as Income, 0 as Outcome from Income
union all
select ExpenseDate, 0, TotalAmount from Outcome
) v
group by [date]
As to what is wrong with your statement, the problem is with the case.
They should use is null rather than when null
CASE WHEN income.TotalAmount IS NULL THEN 0 ELSE income.TotalAmount end,
But a shorter way is to use ISNULL
ISNULL(income.TotalAmount, 0)