create column in for each different value in the table - sql

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.

Related

Calculating percentages per product using aggregate functions and group by

I have a table with 5 rows representing two different products. The columns include the product, sales, discount. I'm trying to calculate the percentage of sales per product that included a discount. The table looks like this:
product
sales
discount
1
10
0
1
10
5
2
20
10
2
20
0
2
20
10
My results should look like the below (which I know because I've calculated this in Excel):
product
perc_discount
1
50.00
2
66.67
For each of the two products we are calculating the count of sales with discount divided by the total count of sales, so for product 1 it would be (1/2)*100 = 50.
My SQL code looks like the below:
SELECT
product,
(SELECT COUNT(*) FROM sales WHERE discount >0)/COUNT(*)*100 AS perc_discount
FROM sales
GROUP BY product
However, the result I'm getting is:
product
perc_discount
1
150.0
2
100.0
It seems to be calculating the total count of discounted sales in the table and diving it by the count of each product and I can't seem to figure out how to change it. Any ideas on how I can improve this?
Thanks.
How about conditional sum?
SQL> select product,
2 round(sum(case when discount > 0 then 1 else 0 end) / count(*) * 100, 2) perc_discount
3 from sales
4 group by product;
PRODUCT PERC_DISCOUNT
---------- -------------
1 50
2 66,67
SQL>
So: add 1 for every discount row per product. Divide that sum with total number of rows per product (that's count). Round the result to 2 decimals (so that it looks prettier).
You can use conditional aggregation. For example:
select
product,
100.0 * count(case when discount <> 0 then 'x' end) / count(*) as perc_discount
from sales
group by product

sum positive and negative values separately

I have a table:
NAME MONEY
Jane 100
Chris -100
Jane 50
Ann -10
Jane -25
Ann 17
And i want to write a query to sum data, in one column should be only positive amount od money in another column only negative. Output should look like this:
NAME SUM_POSITIVE SUM_NEGATIVE
Jane 150 -25
Chris 0 -100
Ann 17 -10
query:
select name, sum(money) from TABLE where money>0 group by name
union
select name, sum(money) from TABLE where money<0 group by name;
shows nearly what i want, but result has duplicate names and two columns instead of three:
NAME SUM
Ann -10
Ann 17
Jane -25
Jane 150
Chris -100
Please help me rewrite my query to correct output.
use case when
select name, sum(case when money>0 then money end) SUM_POSITIVE
,sum(case when money<0 then money end) SUM_NEGATIVE
from TABLE group by name
You are getting duplicate name becase union operator merge only those rows where all column values are same, as Ann contain -10 and 17 which is distinct so its make duplicate
You can do conditional aggregation instead :
select name,
sum(case when money > 0 then money end) as SUM_POSITIVE,
sum(case when money < 0 then money end) as SUM_NEGATIVE
from TABLE
group by name;

How to implement a stored procedure for my case?

I will implement a SSRS summary data report with following data records from one table.
ID Part Type Value
------------------------------------------------------------
1 Payroll State Tax 2010
1 Payroll City Tax 500
1 Payroll Medical 300
2 Payroll State Tax 2000
2 Payroll City Tax 400
3 Payroll FICA 200
1 Refund State Tax -500
1 Refund Medical -100
3 Payroll FICA 200
1 Refund State Tax -500
1 Refund Medical -100
How do I implement a stored procedure to produce following result by summing same Type values for each Part so it is easy to build the SSRS report? Thanks a lot!
Type Payroll Refund Total
State Tax 4010 -500 3600
City Tax 900 0 900
FICA 400 0 400
Medical 300 -100 200
You can use a CTE/subquery with conditional aggregation as
CREATE PROCEDURE YourProcName
AS
SET NOCOUNT ON;
WITH CTE AS
(
SELECT Type,
SUM(CASE WHEN Value > 0 THEN Value ELSE 0 END) payroll,
SUM(CASE WHEN Value < 0 THEN Value ELSE 0 END) refund
FROM YourTable
GROUP BY Type
)
SELECT CTE.*,
CTE.payroll + CTE.refund Total
FROM CTE;
GO;
You can use conditional aggregation:
select type,
sum(case when part = 'Payroll' then value else 0 end) as payroll,
sum(case when part = 'Refund' then value else 0 end) as refund
from t
group by type;
Why would you want a stored procedure when a simple query does what you want? I would strongly recommend a view or table-valued function instead.

SQL Query to get sums among multiple payments which are greater than or less than 10k

I am trying to write a query to get sums of payments from accounts for a month. I have been able to get it for the most part but I have hit a road block. My challenge is that I need a count of the amount of payments that are either < 10000 or => 10000. The business rules are that a single payment may not exceed 10000 but there can be multiple payments made that can total more than 10000. As a simple mock database it might look like
ID | AccountNo | Payment
1 | 1 | 5000
2 | 1 | 6000
3 | 2 | 5000
4 | 3 | 9000
5 | 3 | 5000
So the results I would expect would be something like
NumberOfPaymentsBelow10K | NumberOfPayments10K+
1 | 2
I would like to avoid doing a function or stored procedure and would prefer a sub query.
Any help with this query would be greatly appreciated!
I suggest avoiding sub-queries as much as possible because it hits the performance, specially if you have a huge amount of data, so, you can use something like Common Table Expression instead. You can do the same by using:
;WITH CTE
AS
(
SELECT AccountNo, SUM(Payment) AS TotalPayment
FROM Payments
GROUP BY AccountNo
)
SELECT
SUM(CASE WHEN TotalPayment < 10000 THEN 1 ELSE 0 END) AS 'NumberOfPaymentsBelow10K',
SUM(CASE WHEN TotalPayment >= 10000 THEN 1 ELSE 0 END) AS 'NumberOfPayments10K+'
FROM CTE
You can get the totals per account using SUM and GROUP BY...
SELECT AccountNo, SUM(Payment) AS TotPay
FROM payments
GROUP BY AccountNo
You can use that result to count the number over 10000
SELECT COUNT(*)
FROM (
SELECT AccountNo, SUM(Payment) AS TotPay
FROM payments
GROUP BY AccountNo
)
WHERE TotPay>10000
You can get the the number over and the number under in a single query if you want but that's a but more complicated:
SELECT
COUNT(CASE WHEN TotPay<=10000 THEN 1 END) AS Below10K,
COUNT(CASE WHEN TotPay> 10000 THEN 1 END) AS Above10K
FROM (
SELECT AccountNo, SUM(Payment) AS TotPay
FROM payments
GROUP BY AccountNo
)

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