SQL case two conditions two columns - sql

I have the data as follow:
"Table" computer data
date | property | computer code
---------- -------- -----------
20160131 | companyA | 256584
20160131 | companyB | 987451
to e.t.c
20171020 | companyA | 157489
I want to count the number of computer in each company after 2017-Sep, so I use:
select
computer data
, count (case computer code when property='companyA' and date='20171001' then 1 else 0 end) as CMAnumber
, count (case computer code when property='companyB' and date='20171001' then 1 else 0 end) as CMBnumber
from
[data]
group by
computer data
order by
computer data
but it not work...please help!!
I use SQL server 2014 Management Studio. and the data base from company system
and I want to show it like
date | CMAnumber | CMBnumber
20171001 | 200 | 210
20171002 | 230 | 207
ETC
sorry about that I am a fresh on SQL T.T

You are mixing two case forms.
The serached form has a condition after the when:
CASE WHEN <condition> ..
The simple form has it split: a common operand between case and when and expressions after the when. It implies an equals comparision:
CASE <common operand> WHEN <expression> ...
More about case: http://modern-sql.com/feature/case

If you want to use CASE for count some conditions, and if you choose COUNT function for it, else part of the case should be NULL, otherwise, it counts else condition too. Or you should use SUM instead of COUNT. I updated the script for COUNT function.
And your case using wrong, I corrected it too.
SELECT
[computer data]
, count (case when property='companyA' and date >= '20171001' then 1 end) as CMAnumber
, count (case when property='companyB' and date >= '20171001' then 1 end) as CMBnumber
from
[data]
where
date >= '20171001'
group by
[computer data]
order by
[computer data]

What about this:
SELECT property , COUNT(*)
FROM [data]
WHERE DATE > '20170930'
GROUP BY property ;

You can do a combination of subQuery and group by
select property,count(*) from (select * from [computer data] where date > '20170930') group by property

Related

postgresql total column sum

SELECT
SELECT pp.id, TO_CHAR(pp.created_dt::date, 'dd.mm.yyyy') AS "Date", CAST(pp.created_dt AS time(0)) AS "Time",
au.username AS "User", ss.name AS "Service", pp.amount, REPLACE(pp.status, 'SUCCESS', ' ') AS "Status",
pp.account AS "Props", pp.external_id AS "External", COALESCE(pp.external_status, null, 'indefined') AS "External status"
FROM payment AS pp
INNER JOIN auth_user AS au ON au.id = pp.creator_id
INNER JOIN services_service AS ss ON ss.id = pp.service_id
WHERE pp.created_dt::date = (CURRENT_DATE - INTERVAL '1' day)::date
AND ss.name = 'Some Name' AND pp.status = 'SUCCESS'
id | Date | Time | Service |amount | Status |
------+-----------+-----------+------------+-------+--------+---
9 | 2021.11.1 | 12:20:01 | some serv | 100 | stat |
10 | 2021.12.1 | 12:20:01 | some serv | 89 | stat |
------+-----------+-----------+------------+-------+--------+-----
Total | | | | 189 | |
I have a SELECT like this. I need to get something like the one shown above. That is, I need to get the total of one column. I've tried a lot of things already, but nothing works out for me.
If I understand correctly you want a result where extra row with aggregated value is appended after result of original query. You can achieve it multiple ways:
1. (recommended) the simplest way is probably to union your original query with helper query:
with t(id,other_column1,other_column2,amount) as (values
(9,'some serv','stat',100),
(10,'some serv','stat',89)
)
select t.id::text, t.other_column1, t.other_column2, t.amount from t
union all
select 'Total', null, null, sum(amount) from t
2. you can also use group by rollup clause whose purpose is exactly this. Your case makes it harder since your query contains many columns uninvolved in aggregation. Hence it is better to compute aggregation aside and join unimportant data later:
with t(id,other_column1,other_column2,amount) as (values
(9,'some serv','stat',100),
(10,'some serv','stat',89)
)
select case when t.id is null then 'Total' else t.id::text end as id
, t.other_column1
, t.other_column2
, case when t.id is null then ext.sum else t.amount end as amount
from (
select t.id, sum(amount) as sum
from t
group by rollup(t.id)
) ext
left join t on ext.id = t.id
order by ext.id
3. For completeness I just show you what should be done to avoid join. In that case group by clause would have to use all columns except amount (to preserve original rows) plus the aggregation (to get the sum row) hence the grouping sets clause with 2 sets is handy. (The rollup clause is special case of grouping sets after all.) The obvious drawback is repeating case grouping... expression for each column uninvolved in aggregation.
with t(id,other_column1,other_column2,amount) as (values
(9,'some serv','stat',100),
(10,'some serv2','stat',89)
)
select case grouping(t.id) when 0 then t.id::text else 'Total' end as id
, case grouping(t.id) when 0 then t.other_column1 end as other_column1
, case grouping(t.id) when 0 then t.other_column2 end as other_column2
, sum(t.amount) as amount
from t
group by grouping sets((t.id, t.other_column1, t.other_column2), ())
order by t.id
See example (db fiddle):
(To be frank, I can hardly imagine any purpose other than plain reporting where a column mixes id of number type with label Total of text type.)

SQL Group By and changing the grouped values

I have a table like this:
1 | Madrid | 45000
2 | Berlin | 35000
3 | Berlin | 65000
Now I want to show a result like this:
1 | Madrid | 45000
2 | Berlin | "Different Values"
So basically I want to use a "Group By" and if it is grouped, then change the value of some columns to a manual string.
I thought about using a view, update all values in this view to the string where i have duplications of the grouped column and then use the real query.
I even thought about implementing an assembly into the sql server that does this, but I don't find any good tutorials on this, only that you can do it.
Or has someone an even better idea? (The real tables used here are huge and the sql query does take sometimes up to 3 minutes to perform, so I made this example simple and I didn't wanted to work here with counts on every column to group, because that could take more than just a few minutes.
Something like this should work
select min(id) as id,
name,
case when count(*) = 1
then cast(sum(value) as varchar)
else 'Different values'
end as value
from your_table
group by name
I would do this as:
select min(id) as id, city,
(case when min(value) = max(value)
then cast(max(value) as varchar(255))
else 'Different Values'
end) as result
from t
group by city;
In fact, I might use something more informative than "different values", such as the range:
select min(id) as id, city,
(case when min(value) = max(value)
then cast(max(value) as varchar(255))
else cast(min(value) as varchar(255)) + '-' + cast(max(value) as varchar(255))
end) as result
from t
group by city;

Split date column on the basis of years in the data

I am working with the AdventureWorks2014 database and am using the following query.
select
SUM(Purchasing.PurchaseOrderDetail.OrderQty) as 'Total Quantity',
SUM(Purchasing.PurchaseOrderDetail.LineTotal) as 'Total Amount',
Purchasing.PurchaseOrderHeader.VendorID
from Purchasing.PurchaseOrderDetail
inner join Purchasing.PurchaseOrderHeader
on Purchasing.PurchaseOrderDetail.PurchaseOrderID = Purchasing.PurchaseOrderHeader.PurchaseOrderID
group by Purchasing.PurchaseOrderHeader.VendorID, DATEPART(year,Purchasing.PurchaseOrderHeader.OrderDate)
order by Purchasing.PurchaseOrderHeader.VendorID
This gives me the following output.
|------------------------------------|
|Total Quantity|Total Amount|VendorID|
|15 |694.1655 | 1492|
|288 |12370.239 | 1492|
|45 |1931.7375 | 1492|
|180 |7682.6295 | 1492|
|9350 |150404.1 | 1494|
|1650 |26541.9 | 1494|
|550 |8847.3 | 1494|
|16500 |265419 | 1494|
|------------------------------------|
From what i understand, this is each year's data, i.e,the values 2011,2012,2013 and 2014, for each vendor. Which is why each vendor is repeated 4 times.
I need to have each of these years as a separate column in the output as follows.
|--------------------------------------------------------------------------------|
|Total Quantity|Total Amount|VendorID|2011Amount|2012Amount|2013Amount|2014Amount|
|--------------------------------------------------------------------------------|
Any thoughts?
Pivot Method, make sure you first prepare the query how you want prior to pivoting.
;WITH cte AS (
SELECT
DATEPART(year,poh.OrderDate) as [Year]
,SUM(pod.OrderQty) OVER (PARTITION BY DATEPART(year,poh.OrderDate)) as TotalQuantity
,SUM(pod.LineTotal) OVER (PARTITION BY DATEPART(year,poh.OrderDate)) as TotalAmount
,pod.LineTotal as Amount
FROM
Purchasing.PurchaseOrderDetail pod
INNER JOIN Purchasing.PurchaseOrderHeader poh
ON pod.PurchaseOrderId = poh.PurchaseOrderId
)
SELECT *
FROm
cte
PIVOT (
SUM(Amount)
FOR [Year] IN ([2011],[2012],[2013],[2014])
) p
Conditional Aggregation Method
SELECT
SUM(pod.OrderQty) as TotalQuantity
,SUM(pod.LineTotal) as TotalAmount
,SUM(CASE WHEN DATEPART(year,poh.OrderDate) = 2011 THEN pod.LineTotal ELSE 0 END) as [2011Amount]
,SUM(CASE WHEN DATEPART(year,poh.OrderDate) = 2012 THEN pod.LineTotal ELSE 0 END) as [2012Amount]
,SUM(CASE WHEN DATEPART(year,poh.OrderDate) = 2013 THEN pod.LineTotal ELSE 0 END) as [2013Amount]
,SUM(CASE WHEN DATEPART(year,poh.OrderDate) = 2014 THEN pod.LineTotal ELSE 0 END) as [2014Amount]
FROM
Purchasing.PurchaseOrderDetail pod
INNER JOIN Purchasing.PurchaseOrderHeader poh
ON pod.PurchaseOrderId = poh.PurchaseOrderId
In this case I think I would go with the conditional aggregation method..... Please note I used Table Aliases to refer to the table rather than continuing to type the long names it is a good habit to get into.
This exact code is of course untested because you did not include test data and desired result but the techniques are the most standard way of doing this. Note when more than 1 column is involved in aggregation it is typically easiest to do conditional aggregation.

Get values of one field on the basis of filter

Name Pay Status
Abc 123 1
Abc 456 0
Abc 852 1
I want to get result :
ABC,1431(Sum Of Pay), 975(Sum Of Pay on the basis on Status where Status is 1)
Select sum(Pay),CASE WHEN Status=1 THEN SUM(Pay)
From Table
Group by Pay,Status
Just use Sum use outside the case statement and also remove pay and status from group by instead add name which makes sense
SELECT Name,
Sum(Pay),
Sum(CASE WHEN Status = 1 THEN Pay END)
FROM Table
GROUP BY Name
SELECT Name, SUM(Pay), SUM(CASE WHEN Status = 1 THEN Pay END)
FROM Table
GROUP BY Name

Do subqueries ignore an outer WHERE condition if it has it's own WHERE condition?

I want a SQL query to follow the conditions of a WHERE statement, except those that are subqueries. In the example below, I'd like to get all entries from the past week, but I want the subqueries to ignore that outer WHERE clause, but I'm not sure of how it will behave.
For example:
SELECT
ProductID,
SUM(CASE WHEN from_source = 'button' THEN 1 ELSE 0 END) 'Used Button',
(SELECT COUNT(*) FROM tracking WHERE from_source = 'button') 'Used Button to date'
FROM tracking
WHERE date_entered > (GETDATE() - 7)
GROUP BY ProductID
Expected output, where the second column is calculating based on outer WHERE, and subquery is not looking at the outer WHERE:
ProductID | Used Button | Used Button to date
123 | 5 | 102
456 | 8 | 175
You could write the query just using conditional aggregation:
select sum(case when date_entered > (GETDATE() - 7) then 1 else 0
end) as UsedButton,
count(*) as UsedButtonToDate
from tracking
where from_source = 'button';
This seems like a simpler approach.
By the way, you shouldn't use single quotes for column aliases. Either name the columns with something that doesn't have to be escaped (as above) or use square braces.