How to make a histogram using sums of several columns in SQL - sql

I often make simple count based histograms with SQL 2012 using case statements, like this:
SELECT
count (CASE WHEN a.[Val1]+a.[Val2]+a.[Val3]+a.[Val4]>=0 AND a.[Val1]+a.[Val2]+a.[Val3]+a.[Val4]< 5000000 THEN 1 END) as '5M',
count (CASE WHEN a.[Val1]+a.[Val2]+a.[Val3]+a.[Val4]>=5000000 AND a.[Val1]+a.[Val2]+a.[Val3]+a.[Val4]< 7500000 THEN 1 END) as '7.5M',
count (CASE WHEN a.[Val1]+a.[Val2]+a.[Val3]+a.[Val4]>=7500000 AND a.[Val1]+a.[Val2]+a.[Val3]+a.[Val4]< 10000000 THEN 1 END) as '10M',
count (CASE WHEN a.[Val1]+a.[Val2]+a.[Val3]+a.[Val4]>10000000 THEN 1 END) as '10M+'
FROM [DBNAME].[dbo].[tableone] a inner join [DBNAME].[dbo].[tabletwo] b
on a.IDfield=b.IDfield
Where b.psc=4
But now I need to make a histogram of sums, and I can't figure out how to sum these values by bin, rather than count them. This is what I have tried:
SELECT
CASE WHEN a.[Val1]+a.[Val2]+a.[Val3]+a.[Val4]>=0 AND a.[Val1]+a.[Val2]+a.[Val3]+a.[Val4]< 5000000 THEN sum(a.[Val1]+a.[Val2]+a.[Val3]+a.[Val4]) END as '5M',
CASE WHEN a.[Val1]+a.[Val2]+a.[Val3]+a.[Val4]>=5000000 AND a.[Val1]+a.[Val2]+a.[Val3]+a.[Val4]< 7500000 THEN sum(a.[Val1]+a.[Val2]+a.[Val3]+a.[Val4]) END as '7.5M',
CASE WHEN a.[Val1]+a.[Val2]+a.[Val3]+a.[Val4]>=7500000 AND a.[Val1]+a.[Val2]+a.[Val3]+a.[Val4]< 10000000 THEN sum(a.[Val1]+a.[Val2]+a.[Val3]+a.[Val4]) END as '10M',
CASE WHEN a.[Val1]+a.[Val2]+a.[Val3]+a.[Val4]>10000000 THEN sum(a.[Val1]+a.[Val2]+a.[Val3]+a.[Val4]) END as '10M+'
FROM [DBNAME].[dbo].[tableone] a inner join [DBNAME].[dbo].[tabletwo] b
on a.IDfield=b.IDfield
Where b.psc=4
But that throws a 8120 error - Column 'Val1' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
Could someone point me in a direction as to how to proceed with this?

Related

SQL Countifs function

Hello,
I reach a dead end. I have a table with piecemark_1, piecemark_2, and weld_type.
I wanted to have a final output as per image show.
In excel I would usually use the formula "COUNTIFS+COUNTIFS" but now my data is getting bigger.
I tried to UNION both piecemark together from column piecemark_1 and piecemark_2 to create another table but I do not know how to countifs from another table.
I was wondering how can I solve this issue.
You seems want :
select piecemark, SUM(CASE WHEN WELD_TYPE = 'SW' THEN 1 ELSE 0 END) AS SW,
SUM(CASE WHEN WELD_TYPE = 'FW' THEN 1 ELSE 0 END) AS FW, COUNT(*) AS Total
from t cross apply
( values (piecemark_1), (piecemark_2)
) tt(piecemark)
group by piecemark
having count(*) > 1;
For all piecemark you need to exclude having clause.

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.

Average and case in SQL Server 2012

I'd like to have the average of a column when its bigger than zero.
Select Avg(Case when Column > 0 then Column else 0 end) as Avg
but I'm afraid the else clause is not correct. I want to ignore the zero values in the average.
Remove else part from case statement so the values less than 1 will be NULL.
Null values will be eliminated by the Avg aggregate. So you will get the average of values which are greater then 0. Try this.
Select Avg(Case when [Column]>0 then [Column] end) as [Avg]
DEMO
Without else part in case statement (Expected Average)
SELECT Avg(CASE WHEN a > 0 THEN a END) [Avg]
FROM (SELECT 2 a UNION ALL SELECT 2 UNION ALL SELECT -1) bb
Result : 2
With else part in case statement.
SELECT Avg(CASE WHEN a > 0 THEN a ELSE 0 END) [Avg]
FROM (SELECT 2 a UNION ALL SELECT 2 UNION ALL SELECT -1) bb
Result : 1

nested SQL queries on one table

I am having trouble formulating a query to get the desired output.
This query involves one table and two columns.
First column bld_stat has 4 different values Private, public, Public-Abandoned, Private-Abandoned the other column bld_type, single_flr, multi_flr, trailer, Whs.
I need to get results that look like this:
So far I can get the first two columns but after that I have not been able to logically get a query to work
SELECT bld_stat, COUNT(grade) AS single_flr
FROM (SELECT bld_stat,bld_type
FROM bld_inventory WHERE bld_type = 'single_flr') AS grade
GROUP BY bld_stat,bld_type,grade
The term you are going for is pivoting. I think this should work...no need for the subquery, and I've changed your group by to only bld_stat
SELECT bld_stat,
sum(case when bld_type = 'singl_flr' then 1 else 0 end) AS single_flr,
sum(case when bld_type = 'multi_flr' then 1 else 0 end) AS multi_flr,
sum(case when bld_type = 'trailer' then 1 else 0 end) AS trailer,
sum(case when bld_type = 'whs' then 1 else 0 end) AS WHS
FROM bld_inventory
GROUP BY bld_stat

Use of sum and count inside a case statement in sql

select req.code ,res.code,
case
(
when (req.code==res.code) then 'pass'
when (req.code<>res.code) then 'fail'
/*....2 more case 'when' 'then' statements here*/
end ) result,
req.country ,res.country,
case (when then staments as above)result,
/*.......case stmts upto 70 statemnts*/
from requesttable req full outer join responsetable res on
req.id=res.id
and ....some conditions.
Can anyone tell me how can I sum every column and display the sum as well as the count of records in every column of both tables simultaneously and display count in my query?
My result should be of this sort
code code1 result sum sum1 equivalence country country1 result1 sum sum1
100 100 pass 200000 25000 fail ind aus fail 800000 800000
equivalence
pass
I am trying to prepare a report joining two tables. I am using multiple case statements to accomplish this. I want to display sum of each column and count of each column of both the tables together in a single report. The query that I have is of the following type.
I think this is kind of what you're looking for. For the code and country values displayed on the line it would give you the pass and fail accounts for the combinations displayed and you would have uniqueness on the columns the aggregate is defined on.
Select req.code,
res.code,
Sum(Case When req.code = res.code) Then 1 Else 0 End) As [Pass],
Sum(Case When req.code <> res.code) Then 1 Else 0 End) As [Fail],
req.country,
res.country,
Sum(Case When req.country = res.country) Then 1 Else 0 End) As [Pass],
Sum(Case When req.country <> res.country) Then 1 Else 0 End) As [Fail]
From requesttable req
Full Outer Join responsetable res
On req.id = res.id
Where ...
Group By req.code,
res.code,
req.country,
res.country