total and group multiple column values in a single query - sql

I am looking to get a summary of multiple states from the same column.
select c.brand
sum amount as total
from charges as c
where c.invoive_id is not null
and c.paid = true
group by c.brand
gets me the sum of all completed purchases grouped by brand.
I want to have a separate column in the same query, summed by brand for "c.paid = false"
so I will have:
Brand Total(true) Total(false)
b_one 25 12
b_two 38 16

You seems to have a simple conditional aggregation statement -
SELECT c.brand
,SUM(CASE WHEN c.paid = 'true' THEN amount END) as Total(true)
,SUM(CASE WHEN c.paid = 'false' THEN amount END) as Total(false)
from charges as c
where c.invoive_id is not null
group by c.brand

You don't say which database you are using so I'll assume PostgreSQL. You can usually use a CASE clause to do this. For example:
select
c.brand,
sum(case when c.paid then 1 else 0 end) as total_true,
sum(case when c.paid then 0 else 1 end) as total_false
from charges as c
where c.invoive_id is not null
group by c.brand

In databases that support boolean types, you can often do:
select c.brand,
sum(c.paid) as num_true,
sum(not c.paid) as num_falst
from charges as c
where c.invoive_id is not null
group by c.brand

Related

Is there a way to collect the data and inspect in one pass using groupby function

Sample Data of table_1
Have this Query that returns
select
customer,
SUM(CASE WHEN activity IN ( 'a','b')
THEN 1
ELSE 0 END) AS num_activity_a_or_b
from table_1
group by customer
Results:
Want to extend this to return one more column if for a given code say X1 if the Activity is "a" and "c" then return num_of_a_and_c_activity.
A bit stuck how to collect and inpect the code and activities in one pass.
can we combine windowing function to achieve this.
Please advise and help
UPDATE:
based on the updated results, maybe the below query is what you need
So what i assume is that you need both a and c as well x1 .
So I count distinct activities which are a and c and then do integer division by 2. if only a is present then count distinct =1 but 1/2 =0 in integer division.
It is only 1 when both a and c are present.
select
customer,
SUM(CASE WHEN activity IN ( 'a','b')
THEN 1
ELSE 0
END) AS num_activity_a_or_b,
COUNT(DISTINCT CASE WHEN code IN ('x1') AND activity IN ( 'a','c')
THEN activity
ELSE NULL
END)/2 AS num_activity_a_and_c
from table_1
group by customer
Maybe your query can be
select
customer,
SUM(CASE WHEN activity IN ( 'a','b')
THEN 1
ELSE 0
END) AS num_activity_a_or_b,
SUM(CASE WHEN code IN ('x1') AND activity IN ( 'a','c')
THEN 1
ELSE 0
END) AS num_activity_a_or_c
from table_1
group by customer

Combining multiple rows in a single row

I have SQL Query like this in SSMS
select distinct (b.TransactionNumber),
(case when b.Amount > 0 then c.total else 0 end) as 'Total Sales',
(case when b.TenderID = 1 then b.Amount else 0 end) as 'Cash',
(case when b.TenderID = 20 then b.Amount else 0 end) as 'Gift Certificates'
from [Transaction] c
inner join TenderEntry b on c.TransactionNumber = b.TransactionNumber
but the output is(see image for reference)
This should be the expected output(see image for reference)
I would expect one row per transaction number, especially given your use of select distinct:
select t.TransactionNumber, te.total as total_sales,
sum(case when t.TenderID = 1 then t.Amount else 0 end) as Cash,
sum(case when t.TenderID = 20 then t.Amount else 0 end) as Gift_Certificates
from TenderEntry te join
Transaction t
on te.TransactionNumber = t.TransactionNumber
group by t.TransactionNumber, te.total;
This produces one row per transaction.
Note the changes to the query:
The table aliases are meaningful (i.e. abbreviations of table names) rather than arbitrary letters.
The column aliases do not use single quotes. Only use single quotes for string and date constants.
The column aliases have been simplified so they do not need to be escaped.
It occurs to me that you might want to "list" the cash and gifts in the two columns. This would look like:
select TransactionNumber,
max(case when seqnum = 1 then total end) as total_sales,
sum(case when tenderId = 1 then amount end) as cash,
sum(case when tenderId = 20 then amount end) as Gift_Certificates
from (select t.TransactionNumber, te.total, t.amount, t.TenderID,
row_number() over (partition by t.TransactionNumber, t.TenderId order by t.amount) as seqnum
from TenderEntry te join
Transaction t
on te.TransactionNumber = t.TransactionNumber
where tenderid in (1, 20)
) x
group by t.TransactionNumber, seqnum;
This is only a partial answer, but I put it here because I cannot fit it into comments well enough.
It is likely that you do not want the DISTINCT component in the select. SELECT DISTINCT find all unique rows. So if you have 3 rows which all have some differences, it will show all three. If, on the other hand, there were two rows the same (e.g., they paid for a $100 item with two $50 vouchers) it would just ignore one of them.
Instead, you probably need to become familiar with 'GROUP BY' which allows you to find totals etc across multiple rows.
For example (although not tested)
select
(b.TransactionNumber),
(case when b.Amount > 0 then c.total else 0 end) as 'Total Sales',
SUM(case when b.TenderID = 1 then b.Amount else 0 end) as 'Cash',
SUM(case when b.TenderID = 20 then b.Amount else 0 end) as 'Gift Certificates'
from [Transaction] c
inner join TenderEntry b on c.TransactionNumber = b.TransactionNumber
GROUP BY (b.TransactionNumber, (case when b.Amount > 0 then c.total else 0 end))
In the above, I have removed the DISTINCT, added 'SUM' for the two transaction values (cash/certificates) and the GROUP BY across the TransactionNumber and Total sales (as that seems to be common across the transaction).
For the above data, what that would produce is 1 line of data for TransactionNumber = 1, with sales = 250 (as all the lines have that), and totals for cash and gift certificates (150 and 100 respectively if my maths is correct).
However, that is not your desired answer, - you want this transaction to go over two lines. Firstly, are you sure of that?
If you do, then we need another criteria by which to group them and you will need to specify that e.g., why does this transaction's report need to go over two lines rather than just one?
Other notes
'Transaction' is a special word within SQL Server. You are allowed to use it, but I would consider renaming the table.

how to consolidate information from various rows in to 1 in SQL Server?

I have a table in SQL Server called [orders]:
I have another table called [order_details]:
as you can see, if the media_type is various in [orders] table, there will be 2 corresponding rows in [order_details].
how can i make the below table?
i was trying the method that the admins suggested even before they closed down my original question but what i was getting was the below:
i need this to be like:
You seem to just want conditional aggregation on order_details:
select od.order_id,
sum(case when od.media_type = 'Loose Cartons' then qty else 0 end) as loose_cartons,
sum(case when od.media_type = 'Loose Units' then qty else 0 end) as loose_units
from order_details od
group by od.order_id;
you would just perform an aggregation on the query that got you these results
select [order id]
,max(pallets) as pallets
,max([total cartons]) as [total cartons]
,max(units) as units
,max(sets) as sets
,max(GOH) as GOH
,max([Loose Cartons]) as [Loose Cartons]
,max([Loose Units]) as [Loose Units]
from (<insert query that got you the results with two records >
)
group by [order id]
ok guys sorted.
So i had to create a separate table with just the order_id and 3 more columns with Pallets, Cartons and Sets.
i had to use "max" not "sum" otherwise it would double the quantity.
so what i used was:
create view SSDView_2ND_VB as
select
a.ORDER_ID
,max(case when b.MEDIATYPE_ID = '1' then b.ORDER_DETAIL_QUANTITY else null end) as [Pallets]
,max(case when b.MEDIATYPE_ID = '2' then b.ORDER_DETAIL_QUANTITY else null end) as [Cartons]
,max(case when b.MEDIATYPE_ID = '3' then b.ORDER_DETAIL_QUANTITY else null end) as [Sets]
from
SSDView_1ST_VB as a
left join ORDER_DETAIL as b
on a.ORDER_ID = b.ORDER_ID
group by a.ORDER_ID
The SSDView_1ST_VB was just another view which only had media type 'VARIOUS'.
I would like to thank you all for your help, really appreciate it guys ^^

efficiently compute percentages in hive or sql

SELECT
(CASE WHEN tag=FRAUD THEN 0
ELSE 1 END) fraud_tag,
COUNT(DISTINCT account_id) AS distinct_account_count
FROM fraud_tags a
GROUP BY
(CASE WHEN c.name='riskclass_NotFraud' THEN 0
ELSE 1 END)
RESULT
fraud_tag distinct_account_count
0 100
1 500
Now I want to compute fraud_percentages, number of distinct accounts with fraud_tag=0 over total number of accounts. I have to do it two steps. Any suggestions to make it more efficient?
The easiest way is to do this with the values in one row:
SELECT COUNT(DISTINCT case when tag = FRAUD then account_id end) as distinct_fraud,
COUNT(DISTINCT case when tag = FRAUD then NULL else account_id end) as distinct_notfraud,
(COUNT(DISTINCT case when tag = FRAUD then account_id end)*1.0/count(distinct account_id)
) as fraud_rate
FROM fraud_tags ft;

SQL - How to count yes and no items

I am using SQL Server 2008.
I am writing a query where I need to count how many yesses (1) and how many nos (0 or NULL).
SELECT B.Brand, B.BrandID, COUNT(M.ModelID) AS TotalModels
FROM Brands B LEFT JOIN Models M ON B.BrandID = M.BrandID
GROUP BY B.Brand, B.BrandID
ORDER BY B.Brand
There's another field called IsBestValue in the Model table that will be NULL, 0, or 1. I want to be able to count TotalBestValueYes, TotalBestValueNo, and TotalBestValueNULL.
A long time ago...I use to use something like ..
(CASE WHEN IsBestValue = 1 END) // ADD ONE TO TotalBestValueYes
(CASE WHEN IsBestValue = 0 END) // ADD ONE TO TotalBestValueNo
(CASE WHEN IsBestValue = NULL END) // ADD ONE TO TotalBestValueNULL
Is using CASE in the fashion a good idea? Bad idea? Overkill?
Is there are better way to count yesses and nos and NULLs?
I don't see anything wrong with using the CASE like that if this is what you mean.
SELECT B.Brand,
B.BrandID,
COUNT(M.ModelID) AS TotalModels,
SUM((CASE WHEN M.IsBestValue = 1 THEN 1 ELSE 0 END)) TotalBestValueYes,
SUM((CASE WHEN M.IsBestValue = 0 THEN 1 ELSE 0 END)) TotalBestValueNo,
SUM((CASE WHEN M.IsBestValue IS NULL THEN 1 ELSE 0 END)) TotalBestValueNull,
FROM Brands B
LEFT JOIN Models M ON B.BrandID = M.BrandID
GROUP BY B.Brand,
B.BrandID
ORDER BY B.Brand
The is the perfect case for CASE (pun intended).
CASE is a very well optimized operator and was designed for just such a usage scenario.
The normal syntax for a conditional count is along the lines of:
SELECT SUM (CASE WHEN x=y then 1 ELSE 0 END) as 'XequalsY'
...
select count(nullif(IsBestValue, 0)) as TotalBestValueYes,
count(nullif(IsBestValue, 1)) as TotalBestValueNo,
count(case when IsBestValue is null then 1 end) as TotalBestValueNull