SubQuery accessing parent value - sql

Hello all I am having a issue with this:
Select Customer_Tool_Lookup.ID,
Customer.CustomerName,
(select count(ID) as perDay
FROM CustomerData
WHERE DatetimeInserted >= '2013-04-29 00:00:00.000'
AND DatetimeInserted <= '2013-04-29 11:59:59.599'
AND Customer_ID = Customer_Tool_Lookup.Customer_ID) as DCount,
(select count(ID) as perMonth
FROM CustomerData
WHERE DatetimeInserted >= '2013-04-01 00:00:00.000'
AND DatetimeInserted <= '2013-04-30 11:59:59.599'
AND Customer_ID = Customer_Tool_Lookup.Customer_ID) as mCount,
(select count(ID) as perYear
FROM CustomerData
WHERE DatetimeInserted >= '2013-01-01 00:00:00.000'
AND DatetimeInserted <= '2013-04-30 11:59:59.599'
AND Customer_ID = Customer_Tool_Lookup.Customer_ID) as yCount,
Customer_tool_Lookup.PricePerClick,
Customer_Tool_lookup.MinimumPerMonth,
case
when ClicksPerMonth > (select count(ID) as perMonth
FROM CustomerData
WHERE DatetimeInserted >= '2013-04-01 00:00:00.000'
AND DatetimeInserted <= '2013-04-30 11:59:59.599'
AND Customer_ID = Customer_Tool_Lookup.Customer_ID)
then ClicksPerMonth
else ((select count(ID) as perMonth
FROM CustomerData
WHERE DatetimeInserted >= '2013-04-01 00:00:00.000'
AND DatetimeInserted <= '2013-04-30 11:59:59.599'
AND Customer_ID = Customer_Tool_Lookup.Customer_ID) - Customer_tool_lookup.MinimumPerMonth) * PricePerClick END as TDMonth
FROM Customer_tool_Lookup Left join Customer on Customer.ID = Customer_Tool_Lookup.Customer_ID
I am getting an error:
Invalid objectName 'Customer_tool_Lookup'
It started when I added the and statement at the end of the subquery:
AND Customer_ID = Customer_Tool_Lookup.Customer_ID <--
one each of them.
I normally don't ask SQL questions I have done subqueries before but for some reason I have trouble using parent data.
Thanks!

My suggestion would be to convert those correlated subqueries into a single subquery that you join to. If you use this subquery, then you can access the alias inside of your TDMonth CASE expression:
Select ctl.ID,
c.CustomerName,
cd.DCount,
cd.mCount,
cd.yCount
ctl.PricePerClick,
ctl.MinimumPerMonth,
case
when ClicksPerMonth > cd.mCount
then ClicksPerMonth
else (cd.mCount - ctl.MinimumPerMonth) * PricePerClick
END as TDMonth
from Customer_tool_Lookup ctl
left join Customer c
on c.ID = ctl.Customer_ID
left join
(
select Customer_ID,
COUNT(case
when DatetimeInserted >= '2013-04-29 00:00:00.000'
and DatetimeInserted <= '2013-04-29 11:59:59.599'
then ID end) as DCount,
COUNT(case
when DatetimeInserted >= '2013-04-01 00:00:00.000'
and DatetimeInserted <= '2013-04-30 11:59:59.599'
then ID end) as mCount,
COUNT(case
when DatetimeInserted >= '2013-01-01 00:00:00.000'
and DatetimeInserted <= '2013-04-30 11:59:59.599'
then ID end) as yCount
from CustomerData
group by Customer_ID
) cd
on ctl.Customer_ID = cd.Customer_ID

Related

How can I include more columns other than just percentage column in my sql query result?

When I use the below query I only get percentage column but I want the (buyer_id, buyer_name, created_date,total_work_orders_with_gtv_first_60_days, total_gtv_first_60_days, total_net_amount_first_60_days) to show as columns too. Would really appreciate your help please.
WITH results_cte AS (
SELECT
b.buyer_id,
b.buyer_name,
CAST(b.created_date AS DATE) AS created_date,
COALESCE(wo.total_work_orders_with_gtv_first_60_days, 0) AS total_work_orders_with_gtv_first_60_days,
COALESCE(wo.total_gtv_first_60_days, 0) AS total_gtv_first_60_days,
COALESCE(wo.total_net_amount_first_60_days, 0) AS total_net_amount_first_60_days
FROM dw.buyer b
LEFT JOIN (SELECT wo.buyer_id,
COUNT(CASE WHEN wo.gtv_date < DATEADD(DAY, 60, b.created_date) THEN wo.work_order_id ELSE NULL END) AS total_work_orders_with_gtv_first_60_days,
SUM(CASE WHEN wo.gtv_date < DATEADD(DAY, 60, b.created_date) THEN wo.gtv ELSE NULL END) AS total_gtv_first_60_days,
SUM(CASE WHEN wo.gtv_date < DATEADD(DAY, 60, b.created_date) THEN wo.net_amount ELSE NULL END) AS total_net_amount_first_60_days
FROM dw.work_order wo
JOIN dw.buyer b
ON wo.buyer_id = b.buyer_id
WHERE wo.gtv > 0
GROUP BY wo.buyer_id) wo
ON b.buyer_id = wo.buyer_id
WHERE b.buyer_segmentation = 'S - Self-Service'
AND b.status = 'Active'
AND b.created_date >= DATEADD(YEAR, -1, GETDATE())
)
SELECT (SELECT CAST(count(DISTINCT buyer_id) AS float) FROM results_cte WHERE total_work_orders_with_gtv_first_60_days > 0)
/ (SELECT CAST(count(DISTINCT buyer_id) AS float) FROM results_cte ) AS percentage

Needing Help Separating Data into columns

I'm currently using SQL at work to Query a database in order to display certain information. I have each item that's being pulled as separate entities. Whenever I run the Query my results only show under one column. Is there a way to separate this data into separate columns based on alias?
SELECT
count(o.orderid) AS Current_Daily
FROM
orders o
WHERE
o.ship_dt BETWEEN '2020-11-09 00:00:00' AND '2020-11-15 23:59:59'
AND o.orderstatus = 2
UNION
#UNION ALL
SELECT
count(o.orderid) AS Previous_Daily
FROM
orders o
WHERE
o.ship_dt BETWEEN '2019-11-09 00:00:00' AND '2019-11-15 23:59:59'
AND o.orderstatus = 2
UNION
#UNION ALL
SELECT
count(o.orderid) AS Current_Monthly
FROM
orders o
WHERE
o.ship_dt BETWEEN '2020-11-01 00:00:00' AND '2020-11-15 23:59:59'
AND o.orderstatus = 2
UNION
#UNION ALL
SELECT
count(o.orderid) AS Previous_Monthly
FROM
orders o
WHERE
o.ship_dt BETWEEN '2019-11-01 00:00:00' AND '2019-11-15 23:59:59'
AND o.orderstatus = 2
;
Any Help would be greatly appreciated.
Use conditional aggregation, as in:
select
sum(case when ship_dt >= '2020-11-09' and ship_dt < '2020-11-15' then 1 else 0 end) as current_daily,
sum(case when ship_dt >= '2020-11-01' and ship_dt < '2020-11-15' then 1 else 0 end) as current_monthly,
... -- more conditional "sum()"s if needed
from orders o
where orderstatus = 2
You probably just want conditional aggregation. Something like this:
SELECT SUM(CASE WHEN o.ship_dt >= '2020-11-09' AND o.ship_dt < '2020-11-16' THEN 1 ELSE 0 END) AS Current_Daily,
SUM(CASE WHEN o.ship_dt >= '2020-11-01' AND o.ship_dt < '2020-11-16' THEN 1 ELSE 0 END) AS Current_Monthly,
FROM orders o
WHERE o.orderstatus = 2;
You can add additional columns using similar logic.

Speed up Query Run Time with multiple Case When Expressions

I have the following code below. It is a simple Sum with specific conditions and divided by count distinct function with specific conditions. The problem it is taking too long to run. Right now it is 2 Days and it has not finished running. How can I make this faster? This is part of the code the Case whens are repeated over 100 times as I am tracking over every month.
Select
(sum (case when INSTALLATION_TYPE like'%R' and RATE_FAKT = 'VI' and INvoice_Date between '2018-01-01' and '2018-12-31' then QUANT end)/1000)/
Count (Distinct (case when INSTALLATION_TYPE like'%R' and RATE_FAKT = 'VI' and INvoice_Date between '2018-01-01' and '2018-12-31' then MIRN end) )CY18_GJPERMIRN_VI,
(sum (case when RATE_FAKT = 'VB' and INvoice_Date between '2018-01-01' and '2018-12-31' then QUANT end)/1000)/
Count (Distinct (case when INSTALLATION_TYPE like'%R' and RATE_FAKT = 'VB' and INvoice_Date between '2018-01-01' and '2018-12-31' then MIRN end) )CY18_GJPERMIRN_VB,
(sum (case when INSTALLATION_TYPE like'%B' and RATE_FAKT = 'VI' and INvoice_Date between '2018-01-01' and '2018-12-31' then QUANT end)/1000)/
Count (Distinct (case when INSTALLATION_TYPE like'%B' and RATE_FAKT = 'VI' and INvoice_Date between '2018-01-01' and '2019-12-31' then MIRN end) )CY18_GJPERMIRN_VI_Commercial,
(sum (case when INSTALLATION_TYPE like'%R' and RATE_FAKT = 'VI' and INvoice_Date between '2019-01-01' and '2019-08-31' then QUANT end)/1000)/
Count (Distinct (case when INSTALLATION_TYPE like'%R' and RATE_FAKT = 'VI' and INvoice_Date between '2019-01-01' and '2019-08-31' then MIRN end) )CY19_AUG_GJPERMIRN_VI,
(sum (case when RATE_FAKT = 'VB' and INvoice_Date between '2019-01-01' and '2019-08-31' then QUANT end)/1000)/
Count (Distinct (case when INSTALLATION_TYPE like'%R' and RATE_FAKT = 'VB' and INvoice_Date between '2019-01-01' and '2019-08-31' then MIRN end) )CY19_AUG_GJPERMIRN_VB,
(sum (case when INSTALLATION_TYPE like'%B' and RATE_FAKT = 'VI' and INvoice_Date between '2019-01-01' and '2019-08-31' then QUANT end)/1000)/
Count (Distinct (case when INSTALLATION_TYPE like'%B' and RATE_FAKT = 'VI' and INvoice_Date between '2019-01-01' and '2019-08-31' then MIRN end) )CY19_AUG_GJPERMIRN_VI_Commercial
FROM [Analytics_JGN].[dbo].[VW_BILLINGS]
Where MIRN like '524%';
You need to use dynamic PIVOT query to generate columns dynamically. This link will help you in it.
Because I checked that there are 3 columns (GJPERMIRN_VI, GJPERMIRN_VB, GJPERMIRN_VI_Commercial) are repeating year wise and prefix is CY(Last 2 character of year from Invoice date column)_.
I have changed your query from CASE statement to UNION ALL with CTE. This will little bit faster. Please check below query for your answer.
;WITH CTE_GJPERMIRN
AS
(
SELECT
(SUM(ISNULL(QUANT,0)) / 1000) / ISNULL(COUNT(DISTINCT MIRN),1) AS CY18_GJPERMIRN_VI,
0 AS CY18_GJPERMIRN_VB,
0 AS CY18_GJPERMIRN_VI_Commercial,
0 AS CY19_AUG_GJPERMIRN_VI,
0 AS CY19_AUG_GJPERMIRN_VB,
0 AS CY19_AUG_GJPERMIRN_VI_Commercial
FROM [Analytics_JGN].[dbo].[VW_BILLINGS]
Where MIRN LIKE '524%'
AND INSTALLATION_TYPE LIKE '%R'
AND RATE_FAKT = 'VI'
AND INvoice_Date BETWEEN '2018-01-01' AND '2018-12-31'
UNION ALL
SELECT
0 AS CY18_GJPERMIRN_VI,
(SUM(ISNULL(QUANT,0)) / 1000) / ISNULL(COUNT(DISTINCT MIRN),1) AS CY18_GJPERMIRN_VB,
0 AS CY18_GJPERMIRN_VI_Commercial,
0 AS CY19_AUG_GJPERMIRN_VI,
0 AS CY19_AUG_GJPERMIRN_VB,
0 AS CY19_AUG_GJPERMIRN_VI_Commercial
FROM [Analytics_JGN].[dbo].[VW_BILLINGS]
Where MIRN LIKE '524%'
AND INSTALLATION_TYPE LIKE '%R'
AND RATE_FAKT = 'VB'
AND INvoice_Date BETWEEN '2018-01-01' AND '2018-12-31'
UNION ALL
SELECT
0 AS CY18_GJPERMIRN_VI,
0 AS CY18_GJPERMIRN_VB,
(SUM(ISNULL(QUANT,0)) / 1000) / ISNULL(COUNT(DISTINCT MIRN),1) AS CY18_GJPERMIRN_VI_Commercial,
0 AS CY19_AUG_GJPERMIRN_VI,
0 AS CY19_AUG_GJPERMIRN_VB,
0 AS CY19_AUG_GJPERMIRN_VI_Commercial
FROM [Analytics_JGN].[dbo].[VW_BILLINGS]
Where MIRN LIKE '524%'
AND INSTALLATION_TYPE LIKE '%B'
AND RATE_FAKT = 'VI'
AND INvoice_Date BETWEEN '2018-01-01' AND '2018-12-31' --Consider 2018 year in End Date instead of 2019 in count distinct case statement
UNION ALL
SELECT
0 AS CY18_GJPERMIRN_VI,
0 AS CY18_GJPERMIRN_VB,
0 AS CY18_GJPERMIRN_VI_Commercial,
(SUM(ISNULL(QUANT,0)) / 1000) / ISNULL(COUNT(DISTINCT MIRN),1) AS CY19_AUG_GJPERMIRN_VI,
0 AS CY19_AUG_GJPERMIRN_VB,
0 AS CY19_AUG_GJPERMIRN_VI_Commercial
FROM [Analytics_JGN].[dbo].[VW_BILLINGS]
Where MIRN LIKE '524%'
AND INSTALLATION_TYPE LIKE'%R'
AND RATE_FAKT = 'VI'
AND INvoice_Date BETWEEN '2019-01-01' AND '2019-08-31'
UNION ALL
SELECT
0 AS CY18_GJPERMIRN_VI,
0 AS CY18_GJPERMIRN_VB,
0 AS CY18_GJPERMIRN_VI_Commercial,
0 AS CY19_AUG_GJPERMIRN_VI,
(SUM(ISNULL(QUANT,0)) / 1000) / ISNULL(COUNT(DISTINCT MIRN),1) AS CY19_AUG_GJPERMIRN_VB,
0 AS CY19_AUG_GJPERMIRN_VI_Commercial
FROM [Analytics_JGN].[dbo].[VW_BILLINGS]
Where MIRN LIKE '524%'
AND INSTALLATION_TYPE LIKE '%R'
AND RATE_FAKT = 'VB'
AND INvoice_Date BETWEEN '2019-01-01' AND '2019-08-31'
UNION ALL
SELECT
0 AS CY18_GJPERMIRN_VI,
0 AS CY18_GJPERMIRN_VB,
0 AS CY18_GJPERMIRN_VI_Commercial,
0 AS CY19_AUG_GJPERMIRN_VI,
0 AS CY19_AUG_GJPERMIRN_VB,
(SUM(ISNULL(QUANT,0)) / 1000) / ISNULL(COUNT(DISTINCT MIRN),1) AS CY19_AUG_GJPERMIRN_VI_Commercial
FROM [Analytics_JGN].[dbo].[VW_BILLINGS]
Where MIRN LIKE '524%'
AND INSTALLATION_TYPE LIKE '%B'
AND RATE_FAKT = 'VI'
AND INvoice_Date BETWEEN '2019-01-01' AND '2019-08-31'
)
SELECT
SUM(CG.CY18_GJPERMIRN_VI) AS CY18_GJPERMIRN_VI,
SUM(CG.CY18_GJPERMIRN_VB) AS CY18_GJPERMIRN_VB,
SUM(CG.CY18_GJPERMIRN_VI_Commercial) AS CY18_GJPERMIRN_VI_Commercial,
SUM(CG.CY19_AUG_GJPERMIRN_VI) AS CY19_AUG_GJPERMIRN_VI,
SUM(CG.CY19_AUG_GJPERMIRN_VB) AS CY19_AUG_GJPERMIRN_VB,
SUM(CG.CY19_AUG_GJPERMIRN_VI_Commercial) AS CY19_AUG_GJPERMIRN_VI_Commercial
FROM CTE_GJPERMIRN CG
Note: CY18_GJPERMIRN_VI_Commercial - You may put wrong end date in COUNT(DISTINCT) Invoice date case statement, which I have corrected.
For performance troubleshooting you can try using many separate select statements instead of many case statements in 1 select statement. Something like: (untested)
select *
from (
Select sum(isnull(QUANT,0)/1000/Count(Distinct MIRN) CY18_GJPERMIRN_VI
FROM [Analytics_JGN].[dbo].[VW_BILLINGS]
Where MIRN like '524%'
and INSTALLATION_TYPE like'%R'
and RATE_FAKT = 'VI'
and INvoice_Date between '2018-01-01' and '2018-12-31'
) a
full outer join
(
select sum(isnull(QUANT,0)/1000/Count(Distinct(MIRN) CY18_GJPERMIRN_VB
FROM [Analytics_JGN].[dbo].[VW_BILLINGS]
Where MIRN like '524%'
and RATE_FAKT = 'VB'
and INvoice_Date between '2018-01-01' and '2018-12-31'
) b on 1=1
Or another approach is to use group by instead of case statements -- presuming it is reasonable. The date ranges would still need to be case statements, but RATE_FAKT and INSTALLATION_TYPE could most likely be moved to GROUP BY.
Your query can be optimized in 2-4 steps because of communication problem.1. First you load the require data in Temp table.2. Since you are saying that this is only part of code so consider my script to incomplete as well.
CREATE TABLE #temp
(
INSTALLATION_TYPE VARCHAR(1),
RATE_FAKT VARCHAR(2) ,
INvoice_Date DATETIME,
QUANT INT,
MIRN INT
)
INSERT INTO #temp
(
INSTALLATION_TYPE,
RATE_FAKT,
INvoice_Date,
QUANT,
MIRN
)
SELECT
RIGHT(INSTALLATION_TYPE,1),
RATE_FAKT,
INvoice_Date,
QUANT,
MIRN
FROM [Analytics_JGN].[dbo].[VW_BILLINGS]
WHERE INvoice_Date >= '2018-01-01'
AND INvoice_Date <= '2019-12-31'
SELECT * FROM #temp
DROP TABLE #temp;

SQL Order by the sum of aliases

To preface, this is Microsoft SQL Server. I have several different columns of various earnings from different years. I need to order by the total sales of each given product, but not report it as an actual column. The commented line is how I tried to do it, but it seems you can't order by an alias. How would one go about this?
SELECT
StockItems.StockItemID,
StockItemName,
SUM(CASE WHEN OrderDate >= '2013-01-01'
AND OrderDate < '2014-01-01'
THEN Quantity * OrderLines.UnitPrice END) AS Sales2013,
SUM(CASE WHEN OrderDate >= '2014-01-01'
AND OrderDate < '2015-01-01'
THEN Quantity * OrderLines.UnitPrice END) AS Sales2014,
SUM(CASE WHEN OrderDate >= '2014-01-01'
AND OrderDate < '2015-01-01'
THEN Quantity * OrderLines.UnitPrice END) AS Sales2015,
SUM(CASE WHEN OrderDate >= '2015-01-01'
AND OrderDate < '2016-01-01'
THEN Quantity * OrderLines.UnitPrice END) AS Sales2016
FROM
Warehouse.StockItems
INNER JOIN Sales.OrderLines
ON Warehouse.StockItems.StockItemID = Sales.OrderLines.StockItemID
INNER JOIN Sales.Orders
ON Sales.OrderLines.OrderID = Sales.Orders.OrderID
GROUP BY
StockItems.StockItemID,
StockItemName
--ORDER BY SUM(Sales2013 + Sales2014 + Sales2015 + Sales2016)
Two methods
Put your query as inner query and order on it
put the full formula in order by
query for #1
select * from
(
SELECT
StockItems.StockItemID,
StockItemName,
SUM(CASE WHEN OrderDate >= '2013-01-01'
AND OrderDate < '2014-01-01'
THEN Quantity * OrderLines.UnitPrice END) AS Sales2013,
SUM(CASE WHEN OrderDate >= '2014-01-01'
AND OrderDate < '2015-01-01'
THEN Quantity * OrderLines.UnitPrice END) AS Sales2014,
SUM(CASE WHEN OrderDate >= '2014-01-01'
AND OrderDate < '2015-01-01'
THEN Quantity * OrderLines.UnitPrice END) AS Sales2015,
SUM(CASE WHEN OrderDate >= '2015-01-01'
AND OrderDate < '2016-01-01'
THEN Quantity * OrderLines.UnitPrice END) AS Sales2016
FROM
Warehouse.StockItems
INNER JOIN Sales.OrderLines
ON Warehouse.StockItems.StockItemID = Sales.OrderLines.StockItemID
INNER JOIN Sales.Orders
ON Sales.OrderLines.OrderID = Sales.Orders.OrderID
GROUP BY
StockItems.StockItemID,
StockItemName
) temp
order by SUM(Sales2013 + Sales2014 + Sales2015 + Sales2016)
query for #2
SELECT
StockItems.StockItemID,
StockItemName,
SUM(CASE WHEN OrderDate >= '2013-01-01'
AND OrderDate < '2014-01-01'
THEN Quantity * OrderLines.UnitPrice END) AS Sales2013,
SUM(CASE WHEN OrderDate >= '2014-01-01'
AND OrderDate < '2015-01-01'
THEN Quantity * OrderLines.UnitPrice END) AS Sales2014,
SUM(CASE WHEN OrderDate >= '2014-01-01'
AND OrderDate < '2015-01-01'
THEN Quantity * OrderLines.UnitPrice END) AS Sales2015,
SUM(CASE WHEN OrderDate >= '2015-01-01'
AND OrderDate < '2016-01-01'
THEN Quantity * OrderLines.UnitPrice END) AS Sales2016
FROM
Warehouse.StockItems
INNER JOIN Sales.OrderLines
ON Warehouse.StockItems.StockItemID = Sales.OrderLines.StockItemID
INNER JOIN Sales.Orders
ON Sales.OrderLines.OrderID = Sales.Orders.OrderID
GROUP BY
StockItems.StockItemID,
StockItemName
order by SUM(Quantity * OrderLines.UnitPrice)
SELECT StockItemID
, StockItemName
, Sales2013
, Sales2014
, Sales2015
, Sales2016
, Sales2013 + Sales2014 + Sales2015 + Sales2016 total_sales
FROM
(
SELECT
StockItems.StockItemID,
StockItemName,
SUM(CASE WHEN OrderDate >= '2013-01-01'
AND OrderDate < '2014-01-01'
THEN Quantity * OrderLines.UnitPrice END) AS Sales2013,
SUM(CASE WHEN OrderDate >= '2014-01-01'
AND OrderDate < '2015-01-01'
THEN Quantity * OrderLines.UnitPrice END) AS Sales2014,
SUM(CASE WHEN OrderDate >= '2014-01-01'
AND OrderDate < '2015-01-01'
THEN Quantity * OrderLines.UnitPrice END) AS Sales2015,
SUM(CASE WHEN OrderDate >= '2015-01-01'
AND OrderDate < '2016-01-01'
THEN Quantity * OrderLines.UnitPrice END) AS Sales2016
FROM
Warehouse.StockItems
INNER JOIN Sales.OrderLines
ON Warehouse.StockItems.StockItemID = Sales.OrderLines.StockItemID
INNER JOIN Sales.Orders
ON Sales.OrderLines.OrderID = Sales.Orders.OrderID
GROUP BY
StockItems.StockItemID,
StockItemName
)
ORDER BY total_sales
Add SUM column:
SUM(CASE WHEN OrderDate >= '2013-01-01'
AND OrderDate < '2016-01-01'
THEN Quantity * OrderLines.UnitPrice END) AS Sales_SUM
Then order by Sales_SUM
Well, the best performing solution would require to use a PIVOT, I wrap it in a CTE for better readability:
;WITH pvt AS (
SELECT
StockItems.StockItemID,
StockItemName,
YEAR(OrderDate) AS OrderYear,
Quantity * OrderLines AS SalesTotal,
SUM(Quantity * OrderLines) OVER (PARTITION BY StockItems.StockItemID) AS SalesForStockItemForYear
FROM
Warehouse.StockItems
INNER JOIN Sales.OrderLines
ON Warehouse.StockItems.StockItemID = Sales.OrderLines.StockItemID
INNER JOIN Sales.Orders
ON Sales.OrderLines.OrderID = Sales.Orders.OrderID
WHERE
YEAR(OrderDate) IN (2013,2014,2015,2016)
PIVOT (
SUM(SalesTotal) FOR OrderYear IN ([2013],[2014],[2015],[2016])
)
)
SELECT DISTINCT
pvt.StockItemID,
pvt.StockItemName,
pvt.[2013] as Sales2013,
pvt.[2014] as Sales2014,
pvt.[2015] as Sales2015,
pvt.[2016] as Sales2016
FROM
pvt
ORDER BY
pvt.SalesForStockItemForYear DESC

Compute average for three periods of times

I have the following three queries which get the average price for a product for three specific period of times: all data, last 7 days and last 30 days.
SELECT AVG(Price) AS AggregatedPrice, COUNT(*) AS PCount
FROM dbo.Products
WHERE Id = #id
SELECT AVG(Price) AS AggregatedPrice, COUNT(*) AS PCount
FROM dbo.Products
WHERE Id = #id AND DATEDIFF(day, UpdatedDatetime, getdate()) < 7
SELECT AVG(Price) AS AggregatedPrice, COUNT(*) AS PCount
FROM dbo.Products
WHERE Id = #id AND DATEDIFF(day, UpdatedDatetime, getdate()) < 30
Those three queries give me the right data, but not in the form I want. Is there a way to combine those three queries into one. My final goal is to create a view with all this data on one row.
In addition, it appears to me that the average computed for the 7 days could be reused for the 30 days and all the list. Is there an optimization that I can do?
SELECT #Id
, t1.AggregatedPrice AggregatedPrice_ALL, t1.PCount PCount_ALL
, t2.AggregatedPrice AggregatedPrice_7, t2.PCount PCount_7
, t3.AggregatedPrice AggregatedPrice_30, t3.PCount PCount_30
FROM
(SELECT Id, AVG(Price) AS AggregatedPrice, COUNT(*) AS PCount
FROM dbo.Products
WHERE Id = #id) t1
JOIN
(SELECT Id, AVG(Price) AS AggregatedPrice, COUNT(*) AS PCount
FROM dbo.ApplicationPrice
WHERE Id = #id AND DATEDIFF(day, UpdatedDatetime, getdate()) < 7) t2
ON t1.Id = t2.id
JOIN
(SELECT Id, AVG(Price) AS AggregatedPrice, COUNT(*) AS PCount
FROM dbo.ApplicationPrice
WHERE Id = #id AND DATEDIFF(day, UpdatedDatetime, getdate()) < 30) t3
ON t1.Id = t3.id
Something like this. Make sure to test properly
SELECT
AVG(Price) AS AggregatedPrice
, COUNT(*) AS PCount
, AVG(CASE WHEN DATEDIFF(day, UpdatedDatetime, getdate()) < 7 THEN Price ELSE Null End) AS AggregatedPrice7Days
, SUM(CASE WHEN DATEDIFF(day, UpdatedDatetime, getdate()) < 7 THEN 1 ELSE 0 End) AS AggregatedPrice7Days
, AVG(CASE WHEN DATEDIFF(day, UpdatedDatetime, getdate()) < 30 THEN Price ELSE Null End) AS AggregatedPrice30Days
, SUM(CASE WHEN DATEDIFF(day, UpdatedDatetime, getdate()) < 30 THEN 1 ELSE 0 End) AS AggregatedPrice30Days
FROM
dbo.Products
WHERE
Id = #id
I don't have T-SQL handy to test the syntax, but it should be something like this:
SELECT t1.AggregatedPrice, t1.PCount, t2.AggregatedPrice, t2.PCount, t3.AggregatedPrice, t3.PCount
FROM
(SELECT AVG(Price) AS AggregatedPrice, COUNT(*) AS PCount FROM dbo.Products WHERE Id = #id) t1,
(SELECT AVG(Price) AS AggregatedPrice, COUNT(*) AS PCount FROM dbo.Products WHERE Id = #id AND DATEDIFF(day, UpdatedDatetime, getdate()) < 7) t2,
(SELECT AVG(Price) AS AggregatedPrice, COUNT(*) AS PCount FROM dbo.Products WHERE Id = #id AND DATEDIFF(day, UpdatedDatetime, getdate()) < 30) t3
Try this:
SELECT AVG(Price) AS AggregatedPrice,
COUNT(*) AS PCount,
AVG(CASE WHEN DATEDIFF(day, UpdatedDatetime, getdate()) < 7 THEN Price ELSE NULL END) AS AggregatedWeekPrice,
COUNT(CASE WHEN DATEDIFF(day, UpdatedDatetime, getdate()) < 7 THEN 1 ELSE NULL END) AS PWeekCount,
AVG(CASE WHEN DATEDIFF(day, UpdatedDatetime, getdate()) < 30 THEN Price ELSE NULL END) AS AggregatedMonthPrice,
COUNT(CASE WHEN DATEDIFF(day, UpdatedDatetime, getdate()) < 30 THEN 1 ELSE NULL END) AS PMonthCount,
FROM dbo.Products
WHERE Id = #id