Split date column on the basis of years in the data - sql

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.

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.)

How to query data from two tables and group by two columns

I am using SQL Server and I have two huge tables containing all sorts of data. I would like to retrieve data on how many Latvian or Russian people live in each city.
The language column contains more than two languages but I would like to query only "Latvian" and "Russian"
Table1 (columns worth mentioning):
ID
ProjectID
Phone_nr
City
Table2 (Columns worth mentioning):
ID
ProjectID
Phone_nr
Language
I want the query to retrieve information something like this:
City1(RU) | Amount of Russians
City1(LT) | Amount of Latvians
City2(RU) | Amount of Russians
City2(LT) | Amount of Latvians
.. etc
Or something like this:
City1 | Amount of Russians | Amount of Latvians | Total amount of people
City2 | Amount of Russians | Amount of Latvians | Total amount of people
City3 | Amount of Russians | Amount of Latvians | Total amount of people
.. etc
I am wondering what would be the best solution to this? Should I use join or union or a simple select?
I came up with a query like this:
SELECT DISTINCT top 100 t.city, count(t.city) as 'Total amount of nr in city', count(*), l.language
FROM table1 l, table2 t
WHERE l.phone = t.phone and l.projectID = t.projektID
group by t.city, l.language
I believe the where clause is correct because both tables have phone numbers and Project IDs, it is important that the query selects with this where clause.
Unfortunately this doesn't quite work. It returns rows in this format:
City1 | Amount of y | total amount of numbers in this language
City1 | Amount of x | total amount of numbers in that language
It's close but it's not good enough. Note: I am using select top 100 just for testing, I will select everything once I have the query done right.
Can anyone help or point me in the right direction? Thank you
You can try using conditional aggregation -
SELECT t.city,
count(case when l.language='Russians' then 1 end) as 'Amount of Russians',
count(case when l.language='Latvians' then 1 end) as 'Amount of Latvians',
count(*) as 'Total amount of nr in city'
FROM table1 l inner join table2 t
on l.phone = t.phone and l.projectID = t.projektID
group by t.city
Note: It's always best to use join explicitly.
The logic of #Fahmi is correct. There is one more approach of using SUM instead of COUNT. I am adding the same for additional option to consider.
SELECT t.city,
SUM(case when l.language='Russians' then 1 else 0 end) as 'Amount of Russians',
SUM(case when l.language='Latvians' then 1 else 0 end) as 'Amount of Latvians',
count(*) as 'Total amount of nr in city'
FROM table1 l inner join table2 t
on l.phone = t.phone and l.projectID = t.projektID
group by t.city

SQL case two conditions two columns

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

How can I combine 3 queries into one query and the result form look like schedule table?

I have 3 select queries :
the result of first for heading of my table.(like : select id, name from cars)
the second result show left side of my schedule table shows the date of sales (select date from dates inner join car on date.carid = car.carid where date.date1 > XXX/XX/XX for example)
the third result returns the data for inside the table. and it is the price of each car in each date.
But I don't know how to combine them?
I guess you need something like this Working SQL Server fiddle here
You need either of the following
Pivot feature of SQL Server
Aggregate function with group-by
Query: Pivot feature of SQL Server
SELECT *
FROM
(
SELECT [SALE_DATE], [CAR_NAME], [COST]
FROM CARS_SALES
) AS source
PIVOT
(
MAX(COST)
FOR [CAR_NAME] IN ([BENZ] , [BMW], [RENAULT])
) as pvt;
Query: Aggregate function with group-by
SELECT SALE_DATE,
MAX(CASE WHEN CAR_NAME = 'BENZ' THEN COST ELSE NULL END) [BENZ],
MAX(CASE WHEN CAR_NAME = 'BMW' THEN COST ELSE NULL END) [BMW],
MAX(CASE WHEN CAR_NAME = 'RENAULT' THEN COST ELSE NULL END) [RENAULT]
FROM CARS_SALES
GROUP BY SALE_DATE
Both the Queries give an
output result
as below:
SALE_DATE BENZ BMW RENAULT
09/07/2014 (null) (null) 900
09/08/2014 100 200 300
09/09/2014 400 600 (null)
09/10/2014 700 500 800
It's really unclear, but based on that you've posted, the solution would be something like this:
select cars.name, dates.date, dates.price
from dates
left join cars on (cars.carid=dates.carid)
order by cars.name, dates.date;
This gets the car's name, price and the date in one query. But I don't understand what your third query is for. If you provide more information I'll update this answer.

Need assistance performing a pivot from multiple tables

I preface this by saying I am new to SQL and have been learning on the job thanks to Stack Overflow.
I am running a query from multiple tables (3 in total), and I am trying to get the results for each unique identifier on one row. 1 of the table items has multiple returns, and I am able to write it to where they show as a max command in their own column; however, it still returns multiple rows for the same identifier.
Here's what I have so far:
SELECT tbl.1.field as ID, tbl.2.field as Name, tbl.2.fieldb as Product,
COUNT(*) AS ConfirmedSales
MAX(CASE WHEN tbl.3.field = 'Product1' then 1 else 0 end) as CustomCol1
MAX(CASE WHEN tbl.3.field = 'Product2' then 1 else 0 end) as CustomCol2
FROM tbl.2
LEFT JOIN tbl.2 on tbl.2.x = tbl.1.x
INNER JOIN tbl.3 on tbl.2.x = tbl.3.x
WHERE ((tbl.1.date between '01/01/2014 00:00:00' and 06/30/2014 23:59:59'))
GROUP BY tbl.1.field, tbl.2.field, tbl.2.fieldb
Results return as follows:
Row |ID |Name |CustomCol1 |CustomCol2
1 |8048 |Jon Smith |1 |0
2 |8048 |Jon Smith |0 |1
3 |4044 |Max Williams |0 |0
I would like for the results for CustomCol1 and CustomCol2 to share the same line if the ID is the same. Is this possible?
Consider moving your cases into a subquery like so:
SELECT t.ID, t.name, MAX(s.custom1) AS custom1, MAX(custom2) AS custom2
FROM #tbl1 t
INNER JOIN (SELECT personID
,CASE WHEN s.product = 'product1' THEN 1 ELSE 0 END custom1
,CASE WHEN s.product = 'product2' THEN 1 ELSE 0 END custom2
FROM #sales s) s ON t.ID = s.personID
GROUP BY t.ID, t.Name
This will prevent the duplication you're seeing. If you're ultimate goal is something else, though, give us some more info, and I'm sure someone will have a good answer.