Transpose columns to rows and sum up common column - sql

Basically I have these columns in a temp table, I would like to group them by the dynamic columns (Payment method) to rows and sum up the tax amount based on the payment method. The Tax column will always be there, so you may consider it a static column. The dynamic columns are stored in a variable #PaymentMethod = [Cash], [Card], etc...
Cash | Card | Tax
3.00 0.50
3.00 0.50
5.00 0.70
Expected result:
Pay Method | Tax
Cash 1.00
Card 0.70
How do I achieve this? I've looked up on UNPIVOT however, all the payment methods share the same Tax column field and that is actually the field I want to sum up.

Just use a case for aggregation:
select (case when cash is null and card is null then 'neither'
when cash is not null and card is not null then 'both'
when cash is not null then 'cash'
when credit is not null then 'credit'
end) as pay_method,
sum(tax)
from t
group by (case when cash is null and card is null then 'neither'
when cash is not null and card is not null then 'both'
when cash is not null then 'cash'
when credit is not null then 'credit'
end);

Related

Applying percent change based on unique identifier

I'm calculating margins from a sales table in SQL and I need to reduce sales amounts if there is a discount in a sale based on it's invoice number. For this sample a 25% discount is applied Invoice 123. The total sales amount for invoice 123 is $100.00 but there is a 25% discount applied to that amount. What I want to do is apply that 25% discount to all sales numbers for invoice 123 so I can get the actual revenue number.
Sample Data:
ID Type ProductType Amount
123 Sale Jeans 50.00
123 Sale T-Shirt 30.00
123 Sale Sock 20.00
123 Discount - 25% NULL -25.00
456 Sale Jeans 60.00
456 Sale T-Shirt 40.00
456 Sale Sock 70.00
Expected Result:
ID Type ProductType Amount Actual Amount
123 Sale Jeans 50.00 41.67
123 Sale T-Shirt 30.00 21.67
123 Sale Sock 20.00 11.67
123 Discount - 25% NULL -25.00 0.00
456 Sale Jeans 60.00 60.00
456 Sale T-Shirt 40.00 40.00
456 Sale Sock 70.00 70.00
I've tried creating a new column where I multiple the amount times the discount rate but I can't get the numbers correct because it needs to be applied to the invoice number each discount corresponds to.
I'd like to have a new column that shows the adjusted amount based on the discount rate and then the discount amount showing zero.
One way is to use window functions to calculate the sum of the negative values for an id divided by the number of non negative values for that id by CASE expressions as arguments to the functions. The result of the division can than be deducted from the price. Additionally use a CASE to get zero for the negative values.
SELECT t1.id,
t1.amount,
CASE
WHEN t1.amount <= 0 THEN
0
ELSE t1.amount
+ sum(CASE
WHEN t1.amount < 0 THEN
t1.amount
ELSE
0
END) OVER (PARTITION BY t1.id)
/
count(CASE
WHEN t1.amount >= 0 THEN
1
END) OVER (PARTITION BY t1.id)
END actual_amount
FROM elbat t1;
db<>fiddle

Calculate column amount and get total with order number?

How to calculate each order number amount and total amount with SQL status
Order_no Status Amount
9008258656 P 50.00
9008258656 P 0.00
9008510713 P 50.00
9008510713 P 0.00
Well, it looks like you want a simple aggregated query :
SELECT order_no, count(*) number_of_orders, sum(amount) total_amount
FROM orders
GROUP BY order_no
If you need to filter on a specific status :
SELECT order_no, count(*) number_of_orders, sum(amount) total_amount
FROM orders
WHERE status = 'P'
GROUP BY order_no
If you are looking to keep your individual line numbers (i.e. 4 total records) and not have aggregates (i.e. 2 total records), you can use the sum window function.
SELECT ord.Order_no
, ord.Status
, ord.Amount
, TotalSum = SUM(ord.Amount)OVER(PARTITION BY ord.Order_no, ord.Status)
FROM Orders ord
This would produce the following result:
Order_no Status Amount TotalAmount
9008258656 P 50.00 50.00
9008258656 P 0.00 50.00
9008510713 P 50.00 50.00
9008510713 P 0.00 50.00
Based off the example you provided, there probably is not much value in doing the sum over in this scenario. #GMB's response should suffice. However, there are a lot of cool things you can do with the sum window function such as running totals. For example, if you had an order date column, you can include after the PARTITION BY ord.Order_no, ord.Status ORDER BY ord.Order_date and this would give you a running sum of the amount that increments by each order. I.E:
Order_no Order_date Status Amount RunningTotal
9008258656 1/2/2019 P 50.00 50.00
9008258656 1/3/2019 P 0.00 50.00
9008258656 1/4/2019 P 50.00 100.00
9008258656 1/5/2019 P 0.00 100.00

query that is splitting a column into two

Hello I have an ID column and an amount column at the moment.
A value is represented as a Debit if the amount is positive. A credit if the amount is negative. I'm wondering how can I "Split" my amount column.
Select * from Test.dbo.Accounts
Produces
ID | Amount
1 | 500
2 | -600
So Item 1 is a Debit, Item two is a credit. I want to query the Database so that it displays as followed
ID | Debit | Credit
1 | 500 | null
2 | null |-600
You can use a case statement to find which column the amount belongs in:
SELECT id ,
CASE WHEN amount >= 0 THEN amount
ELSE NULL
END AS debit ,
CASE WHEN amount < 0 THEN amount
ELSE NULL
END AS credit
FROM Test.dbo.Accounts
I assumed 0 should go in debits but that'd be your call.
Select ID, Amount as Debit, null as Credit
From Account
Where Amount >= 0
Union All
Select ID, null as Debit, Amount as Credit
From Account
Where Amount < 0

Create a summarized table using data from table.

I have a table which displays the following information:
order# orderdate Company Itemno itemdesc sales qty price location ref# dept. discount approvedstatus ordertype subrent
AH123 01/23/2013 HRV T1456286 dog leash T 50 10.00 LA NR ACESSORIES 0.00 APPROV
AH123 01/23/2013 HRV T1456286 dog bone T 10 10.00 LA AF ACESSORIES 0.00 APPROV O F
TV1245 05/25/2013 T&T T54895 staples 5 10.00 AB ARC SUPPLIES 0.00 APPROV O F
TV1645 05/25/2013 T&T T54895 paper 10 20.00 AB ARC SUPPLIES 0.00 APPROV O F
Given this table I would like to get a summarized table which would give me the following information:
Location Rev Non-Rev
LA 100.00 500.00
AB 250.00 0.00
In Order words, the total_Price based on the location will only go into Non-Rev if the ref# says 'NR' otherwise it will go into REV column.
I have tried this by inserting everything to a temp table and then using a case statement but I can't use CASE WHEN ref#<>'NR' SUM(price_qty) as it requires me to group it by ref# as well which creates more column than I actually need.
Any help!!!
You were really close:
SELECT Location,
SUM(CASE WHEN [ref#] = 'NR' THEN price_qty END) Rev,
SUM(CASE WHEN [ref#] <> 'NR' THEN price_qty END) [Non-Rev]
FROM YourTable
GROUP BY Location
Not sure I follow, but I think you can use a derived table, which would be your detail plus your derived rev and non-rev columns, and then summarize from that.
Something like:
select
col1,
...
sum(NonRev),
sum(rev)
from
(
select Col1,
...,
case when ref# <> 'NR' then price_qty else 0 end as NonRev,
case when ref# = 'NR' then price_qty else 0 end as rev
from
yourtable
) t1
group by
col1,
...

create column in for each different value in the table

Let us say that I have a table structured like this(using SQL server):
empID INT
payment INT
Now, each employee only gets paid either 50.00 or 100.00. There are two employees earning 50.00 and three earning 100.00.
How would I do a select statement so that the result set was like this:
50.00 100
----- -----
2 3
Where 50.00 and 100.00 are the column headers, and the number below are the actual values. I know that I can do
SELECT payment, COUNT(*)
FROM Student
GROUP BY payment
But that returns the payment in its own column. I want each different payment value in its own column.
Here's how:
select sum(case when payment = 50.00 then 1 else 0 end) as num050,
sum(case when payment = 100.00 then 1 else 0 end) as num100
But, with floating point numbers, you should never do equal comparisons. It is better to do something like:
sum(case when abs(payment - 50) < 0.001 then 1 else 0 end)
or something like that.