SQL Pivot or Cross Tab? - sql

select SALESTABLE.CUSTACCOUNT,
SALESTABLE.salesname,
datename(month,SALESTABLE.SHIPPINGDATECONFIRMED)as Month,
sum(SALESLINE.LineAmount ) SaleAmount
from
SALESTABLE
inner join SALESLINE
on SALESTABLE.SALESID= SALESLINE.SALESID
WHERE SUBSTRING(SALESTABLE.CUSTACCOUNT, 1,2)='O-'
group by SALESTABLE.CUSTACCOUNT,
SALESTABLE.salesname,
datename(month,SALESTABLE.SHIPPINGDATECONFIRMED)
order by SALESTABLE.salesname,
datename(month,SALESTABLE.SHIPPINGDATECONFIRMED)
can i convert this query into pivot i want to show month name at the top of the table like Column Header and sum of LineAmount bellow these month columns

select *
from (select SALESTABLE.CUSTACCOUNT,
SALESTABLE.salesname,
datename(month,SALESTABLE.SHIPPINGDATECONFIRMED)as Month,
SALESLINE.LineAmount
from
SALESTABLE
inner join SALESLINE
on SALESTABLE.SALESID= SALESLINE.SALESID
WHERE SUBSTRING(SALESTABLE.CUSTACCOUNT, 1,2)='O-'
) t pivot (sum (LineAmount) for Month in (January,February,March,April,May,June,July,August,September,October,November,December)) p

Related

I want an SQLquery to find highest MonthlyActiveUsers per month such that each month is aggregated to just ONE row

Finding the highest monthly active users per calendar month in a database where the MONTH column is aggregated such that each month is aggregated to just one row
SELECT
MONTH([OrderDate]) AS Month,
[Name] AS Country,
COUNT([CustomerID]) AS 'Number of Customers Per Month'
FROM
[Sales].[SalesOrderHeader] AS A
LEFT JOIN
[Sales].[SalesOrderDetail] AS B ON A.SalesOrderID = B.SalesOrderID
LEFT JOIN
[Sales].[SalesTerritory] AS C ON A.TerritoryID = C.TerritoryID
GROUP BY
MONTH([OrderDate]), [Name]
ORDER BY
3 DESC
The simplest method uses TOP (1) WITH TIES and ROW_NUMBER() in the ORDER BY:
SELECT TOP (1) WITH TIES MONTH([OrderDate]) AS Month, [Name] AS Country,
COUNT(*) AS [Number of Customers Per Month]
FROM [Sales].[SalesOrderHeader] soh LEFT JOIN
[Sales].[SalesOrderDetail] sod
ON soh.SalesOrderID = sod.SalesOrderID LEFT JOIN
[Sales].[SalesTerritory] st
ON soh.TerritoryID = st.TerritoryID
GROUP BY MONTH([OrderDate]), [Name]
ORDER BY ROW_NUMBER() OVER (PARTITION BY MONTH([OrderDate]) ORDER BY COUNT(*) DESC);
Notes:
Use meaning table aliases! a/b/c are arbitrary. Use table abbreviations!
Qualify all column references. That is USE the table aliases.
Only use single quotes for string and date constants. It is best to use column names that do not need to be escaped. But if you must, use the escape character for your database.

Select Sold and unsold product from same table in SQL Server for last month

I have Database table and trying to write query to find sold and not sold product list from one table.
Table is Below
Expecting Result
How do i get this result? i am using CTE to create Tamp table and with all services and then do left join but it dose give me only product sold in Feb, but i want all product with no sell too.
You can cross join the products and the dates, and then bring the table with a left join:
select
p.product,
t.quantity_sold,
d.yr,
d.mn
from (select distinct product from mytable) p
cross join (select distinct yr, mn from mytable) d
left join mytable t
on t.product = p.product
and t.yr = d.yr
and t.mn = d.mn
This puts nulls for rows with no sale - that's presumably a numeric column so you generally don't want to write a string like 'Not Sold' into it.
If there is a possibility of duplicate (product, yr, mn), you might want to use outer aggregation:
select
p.product,
sum(t.quantity_sold) quantity_sold,
d.yr,
d.mn
from (select distinct product from mytable) p
cross join (select distinct yr, mn from mytable) d
left join mytable t
on t.product = p.product
and t.yr = d.yr
and t.mn = d.mn
group by p.product, d.yr, d.mn

Joining 3 tables in SQL showing all 3 tables

I am a basic user of SQL but need to join 3 tables together to sow a) sales b) returns and c) profit
I currently have the following code
select * from (
select SUM(Return_Amount) , 'Return' as type, monthname(Return_Date) as month_
from returns
group by month_
union
select SUM(Order_Total_Cost) , 'Sales' as type, monthname(Order_Date) as month_
from sales
group by month_
union
select SUM(profit) as profit_ , 'Profit' as type, month_
from(
select sell_price-cost_price as profit , monthname(order_date) month_
from sales
join order_item
on order_item.order_No = sales.order_No
join returns
on returns.order_no = sales.order_No
join supplier
on supplier.Product_ID = order_item.Product_ID
) B group by month_
) A order by month_;
This is showing as below:
387 Return August
182 Sales August
867 Profit August
733 Return July
109 Sales July
646 Profit July
596 Return June
I want it to show with Return, Sales & Profit as separate columns instead of all types listed in one.
Any help would be greatly appreciated.
Thanks
Why not join them?
SELECT x.month_
, x.returns_
, y.sales_
, z.profit_
FROM
(SELECT SUM(Return_Amount) AS returns_
, monthname(Return_Date) AS month_
FROM RETURNS
GROUP BY month_) x
INNER JOIN
(SELECT SUM(Order_Total_Cost) AS sales_
, monthname(Order_Date) AS month_
FROM sales
GROUP BY month_) y ON x.month_ = y.month_
INNER JOIN
(SELECT SUM(profit) AS profit_
, month_
FROM
(SELECT sell_price-cost_price AS profit
, monthname(order_date) month_
FROM sales
INNER JOIN order_item ON order_item.order_No = sales.order_No
INNER JOIN RETURNS ON returns.order_no = sales.order_No
INNER JOIN supplier ON supplier.Product_ID = order_item.Product_ID) B
GROUP BY month_) z ON x.month_ = z.month_
You could turn the three unioned queries to subqueries and join them. This assumes that each subquery always produces one record per month.
Also: you probably want to join and month and year, in case your data spans over multiple years (which eventually happens in any live dataset). I would also recommend using numeric years and month (as returned by year() and month()), which would produce more efficient joins than month names.
select
r.month_name,
r.total_return_amount,
s.total_sales,
p.total_profit
from
(
select
year(return_date) yr,
month(return_date) mh,
monthname(return_date) month_name
sum(return_amount) total_return_amount,
from returns
group by
year(return_date),
month(return_date),
monthname(return_date)
) r
inner join (
select
year(order_date) yr,
month(order_date) mh,
sum(order_total_cost) total_sales
from sales
group by
year(order_date),
month(order_date)
) s on s.yr = r.yr and s.mh = r.mh
inner join (
select
year(order_date) yr,
month(order_date) mh,
sum(sell_price - cost_price) as total_profit ,
from sales
inner join order_item on order_item.order_no = sales.order_no
inner join returns on returns.order_no = sales.order_no
inner join supplier on supplier.product_id = order_item.product_id
group by
year(order_date),
month(order_date)
) p on p.yr = r.yr and p.mh = r.mh

Getting a SUM of the values in INNER JOIN adds up duplicate values

I am running a query which is counting the records on monthly basis from the table.
I am trying to add one extra column called "TotalPrice", I need a sum of all the prices from 'settle' table.
The problem I am facing is because of INNER JOIN, 'SUM' of the prices is adding up multiple prices due to duplicate records which the INNER JOIN is returning. Is there a way to avoid it and get a SUM of the prices from unique records ?
SELECT
CONCAT(year(datetime), '-', month(datetime)) AS YearMonth,
COUNT (DISTINCT a.id) AS TOTAL, SUM(total_price) AS TotalPrice
FROM settle AS a with (nolock)
INNER JOIN transfers b with (nolock) ON b.settleId = a.id
INNER JOIN Fdata AS c with (nolock) ON c.id= b.data
GROUP BY CONCAT(year(datetime), '-', month(datetime))
Thanks in advance.
sql server 2008 onwards:
with CTE as -- A CTE alows us to manipulate the data before we use it, like a derived table
(
select datetime, id, total_price,
row_number() over(partition by id, datetime order by total_price) as rn -- This creates a row number for each combo of id and datetime that appears
FROM settle AS a with (nolock)
INNER JOIN transfers b with (nolock) ON b.settleId = a.id
INNER JOIN Fdata AS c with (nolock) ON c.id= b.data
)
SELECT CONCAT(year(datetime), '-', month(datetime)) AS YearMonth,
COUNT (DISTINCT a.id) AS TOTAL,
SUM(total_price) AS TotalPrice
from CTE
where rn = 1 -- that row_number we created? This selects only the first one, removing duplicates
group by CONCAT(year(datetime), '-', month(datetime))

query with subquery with 1 result(max) for each year

I have to make a query where I show for each year wich shipper had the maximum total cost.
My query now show for each year the total cost of each shipper. So in the result i must have a list of the years, for each year the shipper and the total cost.
Thanks in advance.
select year(OrderDate), s.ShipperID, sum(freight)
from orders o
join shippers s on o.ShipVia = s.ShipperID
group by year(OrderDate),s.ShipperID
Select a.FreightYear, a,ShipperID, a.FreightValue
from
(
select year(OrderDate) FreightYear, s.ShipperID, sum(freight) FreightValue
from orders o
join shippers s on o.ShipVia = s.ShipperID
group by year(OrderDate),s.ShipperID
) a
inner join
(
select FreightYear, max(FrieghtTotal) MaxFreight
from
(
select year(OrderDate) FreightYear, s.ShipperID, sum(freight) FreightTotal
from orders o
join shippers s on o.ShipVia = s.ShipperID
group by year(OrderDate),s.ShipperID
) x
group by FreightYear
) max on max.FreightYear = a.FreightYear and max.MaxFreight = a.FreightValue
order by FreightYear
Inner query a is your original query, getting the value of freight by shipper.
Inner query max gets the max value for each year, and then query max is joined to query a, restricting the rows in a to be those with a value for a year = to the max value for the year.
Cheers -
It's marginally shorter if you use windowing functions.
select shippers_ranked.OrderYear as OrderYear,
shippers_ranked.ShipperId as ShipperId,
shippers_ranked.TotalFreight as TotalFreight
from
(
select shippers_freight.*, row_number() over (partition by shippers_freight.OrderYear order by shippers_freight.TotalFreight desc) as Ranking
from
(
select year(OrderDate) as OrderYear,
s.ShipperID as ShipperId,
sum(freight) as TotalFreight
from orders o
inner join shippers s on o.ShipVia = s.ShipperID
group by year(OrderDate), s.ShipperID
) shippers_freight
) shippers_ranked
where shippers_ranked.Ranking = 1
order by shippers_ranked.OrderYear
;
You need to decide what you would like to happen if two shippers have the same TotalFreight for a year - as the code above stands you will get one row (non-deterministically). If you would like one row, I would add ShipperId to the order by in the over() clause so that you always get the same row. If in the same TotalFreight case you would like multiple rows returned, use dense_rank() rather than row_number().