I have my sql tables and query as shown below :
CREATE TABLE #ABC([Year] INT, [Month] INT, Stores INT);
CREATE TABLE #DEF([Year] INT, [Month] INT, SalesStores INT);
CREATE TABLE #GHI([Year] INT, [Month] INT, Products INT);
INSERT #ABC VALUES (2013,1,1);
INSERT #ABC VALUES (2013,1,2);
INSERT #ABC VALUES (2013,2,3);
INSERT #DEF VALUES (2013,1,4);
INSERT #DEF VALUES (2013,1,5);
INSERT #DEF VALUES (2013,2,6);
INSERT #GHI VALUES (2013,1,7);
INSERT #GHI VALUES (2013,1,8);
INSERT #GHI VALUES (2013,2,9);
INSERT #GHI VALUES (2013,3,10);
My current query is
I have #Year and #Month as parameters , both integers , example #Year = '2013' , #Month = '11'
SELECT T.[Year],
T.[Month]
-- select the sum for each year/month combination using a correlated subquery (each result from the main query causes another data retrieval operation to be run)
,
(SELECT SUM(Stores)
FROM #ABC
WHERE [Year] = T.[Year]
AND [Month] = T.[Month]) AS [Sum_Stores],
(SELECT SUM(SalesStores)
FROM #DEF
WHERE [Year] = T.[Year]
AND [Month] = T.[Month]) AS [Sum_SalesStores],
(SELECT SUM(Products)
FROM #GHI
WHERE [Year] = T.[Year]
AND [Month] = T.[Month]) AS [Sum_Products]
FROM (
-- this selects a list of all possible dates.
SELECT [Year],
[Month]
FROM #ABC where [Year] = #Year and [Month] = #Month
UNION
SELECT [Year],
[Month]
FROM #DEF where [Year] = #Year and [Month] = #Month
UNION
SELECT [Year],
[Month]
FROM #GHI where [Year] = #Year and [Month] = #Month) AS T;
Which returns
+------+-------+------------+-----------------+--------------+
| Year | Month | Sum_Stores | Sum_SalesStores | Sum_Products |
+------+-------+------------+-----------------+--------------+
| 2013 | | | | |
| 2013 | | | | |
| 2013 | | | | |
+------+-------+------------+-----------------+--------------+
What I want to do is to add more columns to the query which show the difference from the last month. as shown below.
Example : The Diff beside the Sum_Stores shows the difference in the Sum_Stores from last month to this month.
Something like this :
+------+-------+------------+-----------------+-----|-----|---+-----------------
| Year | Month | Sum_Stores |Diff | Sum_SalesStores |Diff | Sum_Products |Diff|
+------+-------+------------+-----|------------+----|---- |----+--------------|
| 2013 | | | | | | | |
| 2013 | | | | | | | |
| 2013 | | | | | | | |
+------+-------+------------+-----|------------+--- |-----|----+---------| ----
Can anyone tell me how I can modify this to achive my goal.
You ca use a CTE and then self join to get the desired result.
Fiddle Here
;WITH DATA AS (
SELECT T.[Year],
T.[Month]
-- select the sum for each year/month combination using a correlated subquery (each result from the main query causes another data retrieval operation to be run)
,
(SELECT SUM(Stores)
FROM #ABC
WHERE [Year] = T.[Year]
AND [Month] = T.[Month]) AS [Sum_Stores],
(SELECT SUM(SalesStores)
FROM #DEF
WHERE [Year] = T.[Year]
AND [Month] = T.[Month]) AS [Sum_SalesStores],
(SELECT SUM(Products)
FROM #GHI
WHERE [Year] = T.[Year]
AND [Month] = T.[Month]) AS [Sum_Products]
FROM (
-- this selects a list of all possible dates.
SELECT [Year],
[Month]
FROM #ABC where [Year] = #Year and [Month] = #Month
UNION
SELECT [Year],
[Month]
FROM #DEF where [Year] = #Year and [Month] = #Month
UNION
SELECT [Year],
[Month]
FROM #GHI where [Year] = #Year and [Month] = #Month
) AS T )
SELECT d1.year,d1.month ,
d1.Sum_Stores , ( isnull(d2.Sum_Stores,0) -d1.Sum_Stores ) AS storeDiff ,
d1.Sum_SalesStores ,( isnull(d2.Sum_SalesStores,0) -d1.Sum_SalesStores ) AS salesStoresDiff,
d1.Sum_Products , ( isnull(d2.Sum_Products,0) -d1.Sum_Products ) AS prodDiff
-- self joining on month -1 to get previous month data
FROM DATA AS d1 LEFT OUTER JOIN DATA AS d2 ON d2.month = d1.month -1
The above query is for illustrative purposes only.The query provided works correctly for the sample data as it contains the data for a year only. You should apply appropriate logic in the on clause of the left outer join to retrieve data which has input data of more than one year.
Try This:
I created a temp table #XYZ with your data and used that to subtract the previous months data. I have to create 2 more variable to take care of spanning years.
If you have any questions, let me know
DECLARE #Year varchar(4)
SET #Year = '2013'
DECLARE #Month varchar(2) set #Month = '1'
DECLARE #DiffYear varchar(4)
Set #DiffYear = DATEPART(yyyy, DATEADD(m,-1,(#Month+'/1/'+#Year) ))
DECLARE #DiffMonth varchar(2)
set #DiffMonth= DATEPART(mm, DATEADD(m,-1,(#Month+'/1/'+#Year) ))
SELECT T.[Year],
T.[Month]
-- select the sum for each year/month combination using a correlated subquery (each result from the main query causes another data retrieval operation to be run)
,
(SELECT SUM(Stores)
FROM #ABC
WHERE [Year] = T.[Year]
AND [Month] = T.[Month]) AS [Sum_Stores],
(SELECT SUM(SalesStores)
FROM #DEF
WHERE [Year] = T.[Year]
AND [Month] = T.[Month]) AS [Sum_SalesStores],
(SELECT SUM(Products)
FROM #GHI
WHERE [Year] = T.[Year]
AND [Month] = T.[Month]) AS [Sum_Products]
INTO #XYZ
FROM (
-- this selects a list of all possible dates.
SELECT [Year],
[Month]
FROM #ABC --where [Year] = #Year and [Month] = #Month
UNION
SELECT [Year],
[Month]
FROM #DEF --where [Year] = #Year and [Month] = #Month
UNION
SELECT [Year],
[Month]
FROM #GHI --where [Year] = #Year and [Month] = #Month
)
AS T;
SELECT T.[Year],
T.[Month]
-- select the sum for each year/month combination using a correlated subquery (each result from the main query causes another data retrieval operation to be run)
,
(SELECT SUM(Stores)
FROM #ABC
WHERE [Year] = T.[Year]
AND [Month] = T.[Month]) AS [Sum_Stores],
ISNULL((SELECT SUM(Stores)
FROM #ABC
WHERE [Year] = T.[Year]
AND [Month] = T.[Month]),0) - ISNULL((SELECT SUM([Sum_Stores])
FROM #XYZ
WHERE [Year] = #DiffYear
AND [Month] = #DiffMonth),(SELECT SUM(Stores)
FROM #ABC
WHERE [Year] = T.[Year]
AND [Month] = T.[Month])) AS [DIFF_Sum_Stores],
(SELECT SUM(SalesStores)
FROM #DEF
WHERE [Year] = T.[Year]
AND [Month] = T.[Month]) AS [Sum_SalesStores],
ISNULL((SELECT SUM(SalesStores)
FROM #DEF
WHERE [Year] = T.[Year]
AND [Month] = T.[Month]),0) -
ISNULL((SELECT SUM([Sum_SalesStores])
FROM #XYZ
WHERE [Year] = #DiffYear
AND [Month] = #DiffMonth),(SELECT SUM(SalesStores)
FROM #DEF
WHERE [Year] = T.[Year]
AND [Month] = T.[Month])) AS [DIFF_Sum_SalesStores],
(SELECT SUM(Products)
FROM #GHI
WHERE [Year] = T.[Year]
AND [Month] = T.[Month]) AS [Sum_Products],
ISNULL((SELECT SUM(Products)
FROM #GHI
WHERE [Year] = T.[Year]
AND [Month] = T.[Month]),0) -
ISNULL((SELECT SUM([Sum_Products])
FROM #XYZ
WHERE [Year] = #DiffYear
AND [Month] = #DiffMonth),(SELECT SUM(Products)
FROM #GHI
WHERE [Year] = T.[Year]
AND [Month] = T.[Month])) AS [Diff_Sum_Products]
FROM (
-- this selects a list of all possible dates.
SELECT [Year],
[Month]
FROM #ABC where [Year] = #Year and [Month] = #Month
UNION
SELECT [Year],
[Month]
FROM #DEF where [Year] = #Year and [Month] = #Month
UNION
SELECT [Year],
[Month]
FROM #GHI where [Year] = #Year and [Month] = #Month
)
AS T;
Related
I have four tables in my database which is Star Schema Design. Those tables are
Product_DM (Product_Id, Product_Name)
Shop_DM (Branch_Id, Branch_Name, Branch_State)
Date_DM (Date_Id as Date, Day, Month and Year). Day and Month and Year values are populated based on Date_Id.
Revenue_FT (Product_id, Branch_Id, Date_Id, Quantity)
What I want to have is I want to look at 5 BRANCH OR SHOP which sells most products last five years of Boxing day.
SELECT
RF.BRANCH_ID,
SD.BRANCH_NAME,
SD.BRANCH_STATE,
PD.PRODUCT_NAME,
SELF_RF.TOTAL,
FORMAT ( DD.[date], 'd', 'en-US' ) AS 'Great Britain English Result'
FROM
PRODUCT_DM AS PD,
SHOP_DM AS SD,
DATE_DM AS DD,
REVENUE_FT AS RF
JOIN
(SELECT BRANCH_ID, [date], SUM(quantity) AS TOTAL
FROM REVENUE_FT
GROUP BY BRANCH_ID, [date]) AS SELF_RF ON SELF_RF.BRANCH_ID = RF.BRANCH_ID
AND SELF_RF.[date] = RF.[date]
WHERE
RF.BRANCH_ID = SD.BRANCH_ID
AND SD.BRANCH_STATE = 'NSW'
AND RF.[date] = DD.[date]
AND DD.[day] = 26
AND DD.[month] = 12
AND DD.[year] BETWEEN 2012 AND 2018
ORDER BY
SELF_RF.TOTAL DESC;
This is the query I have and this is the result:
The problem is it is not summing up different products and different dates (for example 12/26/2013 and 12/26/2014 should also sum up). I know I am doing something wrong in my query but I needed a hand.
See an example below where you're able to get the top 5 branch / shops which have had the highest sales over the past 5 boxing days.
It's an example based off your listed table structure above.
;with GetBranchDetailsAndData
as
(
--Joins the date table, sales, and shop details to get the branch details and quantity per transaction
SELECT
c.Branch_Id,
c.Branch_Name,
c.Branch_State,
a.Quantity
FROM
Revenue_FT a
INNER JOIN
DATE_DM b
ON
a.Date_Id = b.Date_Id
INNER JOIN
Shop_DM c
ON
c.Branch_Id = a.Branch_Id
WHERE
[DAY] = 26 AND
[Month] = 12
AND [Year] BETWEEN 2012 AND 2017 --Boxing days in 2012 - 2017
--You could also filter on a specific state in the where clause
),
SUMDetailsAndData
as
(
SELECT
Branch_ID,
Branch_Name,
Branch_State,
SUM(Quantity) as [Quantity] --Sum quantity per branch
FROM
GetBranchDetailsAndData
GROUP BY
Branch_ID,
Branch_Name,
Branch_State
),
GetTop5
as
(
SELECT
Branch_ID,
Branch_Name,
Branch_State,
Quantity,
DENSE_RANK() OVER(ORDER BY Quantity DESC) as [QuantityOrder] --DENSE RANK to get the quantity order
FROM
SUMDetailsAndData
)
SELECT
*
FROM
GetTop5
WHERE
QuantityOrder <= 5 --Where the quantity order less or equal to 5. This will return multiple rows if there is multiple with the same number in the top 5.
ORDER BY
QuantityOrder
Here is a snippet below which I used to generate testing data.
--Create tables
CREATE TABLE Product_DM (Product_Id bigint identity(1,1), Product_Name NVARCHAR(200))
CREATE TABLE Shop_DM (Branch_Id bigint identity(1,1), Branch_Name NVARCHAR(100), Branch_State NVARCHAR(100))
CREATE TABLE Date_DM (Date_Id bigint identity(1,1), [Day] int, [Month] int, [Year] int)
CREATE TABLE Revenue_FT (Product_id bigint, Branch_Id bigint, Date_Id bigint, Quantity bigint)
--Insert Data
INSERT INTO Product_DM (Product_Name) VALUES ('Test Product'),('Test Product2')
INSERT INTO Shop_DM (Branch_Name, Branch_State) VALUES
('Branch1', 'State1'), ('Branch2', 'State1'), ('Branch3', 'State1'), ('Branch4', 'State1'), ('Branch5', 'State1'),
('Branch6', 'State1'), ('Branch7', 'State1'), ('Branch8', 'State1'), ('Branch9', 'State1'), ('Branch10', 'State1')
DECLARE #DateStart date = '2010-01-01', #DateEnd date = '2018-01-01'
WHILE(#DateStart <= #DateEnd)
BEGIN
INSERT INTO DATE_DM ([day], [month], [year]) VALUES (DATEPART(dd, #datestart), DATEPART(MM, #datestart), DATEPART(YYYY, #datestart))
SET #DateStart = DATEADD(dd, 1, #DateStart)
END
--Insert random product sales
DECLARE #MinProduct int = 1, #MaxProduct int = 2
DECLARE #MinBranch int = 1, #MaxBranch int = 10
DECLARE #MinDate int = 1, #MaxDate int = 2923
DECLARE #Startloop int = 1, #EndLoop int = 200000
WHILE #Startloop <= #EndLoop
BEGIN
INSERT INTO Revenue_FT VALUES (
ROUND(((#MaxProduct - #MinProduct) * RAND() + #MinProduct), 0),
ROUND(((#MaxBranch - #MinBranch) * RAND() + #MinBranch), 0),
ROUND(((#MaxDate - #MinDate) * RAND() + #MinDate), 0), 1)
SET #Startloop = #Startloop + 1
END
Example output below:
CREATE PROCEDURE [dbo].[CalendarMonthly]
(
#FROMDATE VARCHAR(25)
)
AS
BEGIN
SET NOCOUNT ON
DECLARE #ADate DATETIME
DECLARE #MonthCount INT
SET #ADate = #FROMDATE
SET #MonthCount = (SELECT DAY(EOMONTH(#ADate)))
DECLARE #tmpTable TABLE
(
TRoomID INT, DAY1 INT, DAY2 INT, DAY3 INT, DAY4 INT, DAY5 INT, DAY6 INT, DAY7 INT
)
INSERT INTO #tmpTable
SELECT RM.ROOMID,
0,0,0,0,0,0,0
FROM RoomMaster AS RM
LEFT JOIN RoomTypes AS RT ON RM.RoomTypeID = RT.RoomTypeID
WHERE RM.RoomMasterStatus <> 99
DECLARE #RoomID INT
DECLARE #ForDate DATE
DECLARE #dtFromDate DATE
DECLARE #dtToDate DATE
SET #dtFromDate = CONVERT(DATE,#FromDate)
SET #ForDate = #dtFromDate
SET #dtToDate = CONVERT(DATE,CONVERT(VARCHAR,YEAR(#dtFromDate)) +'-'+ CONVERT(VARCHAR,MONTH(DATEADD(M,1,#dtFromDate)))+'-1')
SET #dtToDate = DATEADD(D,-1,#dtToDate)
DECLARE #DayCount INT
WHILE #ForDate <= #dtToDate
BEGIN
SET #DayCount = DAY(#ForDate)
IF #DayCount = 1
BEGIN
-- Checkin
UPDATE #tmpTable SET DAY1 = 1
FROM #tmpTable TT
JOIN RoomCheckinDetails AS RCD ON RCD.RoomID = TT.TRoomID
JOIN RoomCheckinMaster AS RCM ON RCM.CheckinID = RCD.CheckinID
WHERE CONVERT(DATE,RCD.CheckinDate) = #ForDate
AND RCD.RoomID = TT.TRoomID
-- Expected Checkin
UPDATE #tmpTable SET DAY1 = 8
FROM #tmpTable TT
JOIN RoomBookingDetails AS RBD ON RBD.RoomID = TT.TRoomID
JOIN RoomBookingMaster AS RBM ON RBM.ReservationID = RBD.ReservationID
WHERE CONVERT(DATE,RBD.ExpectedCheckinDate) = #ForDate
AND RBD.RoomID = TT.TRoomID
END
ELSE IF #DayCount = 2
.
.
.
.
.
.
---upto Day count 7
SET #ForDate = DATEADD(Day,1,#ForDate)
END
SELECT * FROM #tmpTable
END
My question is:
ex: checkindate = 04/06/2017, checoutdate = 9/06/2017 in compare two date I have update to columns day1 to columns day6 values is 0.
Instead of creating a temporary table and using a cursor to update each set of columns, this is a set based solution that avoids all of that.
For the first part, if you just need 7 days then you can use a simple values tally table with a common table expression and the Table Value Constructor (Transact-SQL):
declare #fromdate date = '20170605';
;with dates as (
select
[Date]=convert(date,dateadd(day,rn-1,#fromdate))
, rn
from (values (1),(2),(3),(4),(5),(6),(7)) t(rn)
)
Otherwise, you can generate an adhoc table of dates using stacked ctes in a common table expression like this:
declare #fromdate date = '20170605';
declare #thrudate date = dateadd(day,6,#fromdate)
;with n as (select n from (values(0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) t(n))
, dates as (
select top (datediff(day, #fromdate, #thrudate)+1)
[Date]=convert(date,dateadd(day,row_number() over(order by (select 1))-1,#fromdate))
, rn = row_number() over(order by (select 1))
from n as deka cross join n as hecto cross join n as kilo
cross join n as tenK cross join n as hundredK
order by [Date]
)
Then cross join the dates with roommaster, and left join both the checkin and booking tables to see if a room has a reservation or is currently occupied:
, cte as (
select
rm.roomid
, d.rn
, Value = case
when rcd.roomid is not null then 1
when rbd.roomid is not null then 8
else 0
end
from dates d
cross join roommaster rm
left join roomcheckindetails rcd
on rm.roomid = rcd.roomid
and d.date >= rcd.checkindate
and d.date <= rcd.checkoutdate
left join roombookingdetails rbd
on rm.roomid = rbd.roomid
and d.date >= rbd.expectedcheckindate
and d.date <= rbd.expectedcheckoutdate
where rm.roommasterstatus <> 99
)
Then for the last piece, you can use conditional aggregation or pivot() (pick one) like so:
select
roomid
, Day1 = min(case when rn = 1 then value end)
, Day2 = min(case when rn = 2 then value end)
, Day3 = min(case when rn = 3 then value end)
, Day4 = min(case when rn = 4 then value end)
, Day5 = min(case when rn = 5 then value end)
, Day6 = min(case when rn = 6 then value end)
, Day7 = min(case when rn = 7 then value end)
from cte
group by roomid
select
roomid
, Day1 = [1]
, Day2 = [2]
, Day3 = [3]
, Day4 = [4]
, Day5 = [5]
, Day6 = [6]
, Day7 = [7]
from cte
pivot (min(value) for rn in ([1],[2],[3],[4],[5],[6],[7]))p
rextester demo with conditional aggregation: http://rextester.com/RUJ98491
rextester demo with pivot(): http://rextester.com/YNKU89188
both return the same results for my demo data:
+--------+------+------+------+------+------+------+------+
| roomid | Day1 | Day2 | Day3 | Day4 | Day5 | Day6 | Day7 |
+--------+------+------+------+------+------+------+------+
| 2 | 1 | 1 | 1 | 1 | 0 | 0 | 0 |
| 3 | 0 | 8 | 8 | 8 | 8 | 0 | 0 |
+--------+------+------+------+------+------+------+------+
Number and Calendar table reference:
Generate a set or sequence without loops - 2 - Aaron Bertrand
The "Numbers" or "Tally" Table: What it is and how it replaces a loop - Jeff Moden
Creating a Date Table/Dimension in sql Server 2008 - David Stein
Calendar Tables - Why You Need One - David Stein
Creating a date dimension or calendar table in sql Server - Aaron Bertrand
I have my database table ABC as shown below :
ItemId Month Year Sales
1 1 2013 333
1 2 2013 454
2 1 2013 434
and so on .
I would like to write a query to find the top 3 items that have had the highest increase in sales from last month to this month , so that I see somethinglike this in the output.
Output :
ItemId IncreaseInSales
1 +121
9 +33
6 +16
I came up to here :
select
(select Sum(Sales) from ABC where [MONTH] = 11 )
-
(select Sum(Sales) from ABC where [MONTH] = 10)
I cannot use a group by as it is giving an error . Can anyone point me how I can
proceed further ?
Assuming that you want the increase for a given month, you can also do this with an aggregation query:
select top 3 a.ItemId,
((sum(case when year = #YEAR and month = #MONTH then 1.0*sales end) /
sum(case when year = #YEAR and month = #MONTH - 1 or
year = #YEAR - 1 and #Month = 1 and month = 12
then sales end)
) - 1
) * 100 as pct_increase
from ABC a
group by a.ItemId
order by pct_increase desc;
You would put the year/month combination you care about in the variables #YEAR and #MONTH.
EDIT:
If you just want the increase, then do a difference:
select top 3 a.ItemId,
(sum(case when year = #YEAR and month = #MONTH then 1.0*sales end) -
sum(case when year = #YEAR and month = #MONTH - 1 or
year = #YEAR - 1 and #Month = 1 and month = 12
then sales
end)
) as difference
from ABC a
group by a.ItemId
order by difference desc;
Here is the SQL Fiddle that demonstrates the below query:
SELECT TOP(3) NewMonth.ItemId,
NewMonth.Month11Sales - OldMonth.Month10Sales AS IncreaseInSales
FROM
(
SELECT s1.ItemId, Sum(s1.Sales) AS Month11Sales
FROM ABC AS s1
WHERE s1.MONTH = 11
AND s1.YEAR = 2013
GROUP BY s1.ItemId
) AS NewMonth
INNER JOIN
(
SELECT s2.ItemId, Sum(s2.Sales) AS Month10Sales
FROM ABC AS s2
WHERE s2.MONTH = 10
AND s2.YEAR = 2013
GROUP BY s2.ItemId
) AS OldMonth
ON NewMonth.ItemId = OldMonth.ItemId
ORDER BY NewMonth.Month11Sales - OldMonth.Month10Sales DESC
You never mentioned if you could have more than one record for an ItemId with the same Month, so I made the query to handle it either way. Obviously you were lacking the year = 2013 in your query. Once you get past this year you will need that.
Another option could be something on these lines:
SELECT top 3 a.itemid, asales-bsales increase FROM
(
(select itemid, month, sum(sales) over(partition by itemid) asales from ABC where month=2
and year=2013) a
INNER JOIN
(select itemid, month, sum(sales) over(partition by itemid) bsales from ABC where month=1
and year=2013) b
ON a.itemid=b.itemid
)
ORDER BY increase desc
if you need to cater for months without sales then you can do a FULL JOIN and calculate increase as isnull(asales,0) - isnull(bsales,0)
You could adapt this solution based on PIVOT operator:
SET NOCOUNT ON;
DECLARE #Sales TABLE
(
ItemID INT NOT NULL,
SalesDate DATE NOT NULL,
Amount MONEY NOT NULL
);
INSERT #Sales (ItemID, SalesDate, Amount)
VALUES
(1, '2013-01-15', 333), (1, '2013-01-14', 111), (1, '2012-12-13', 100), (1, '2012-11-12', 150),
(2, '2013-01-11', 200), (2, '2012-12-10', 150), (3, '2013-01-09', 900);
-- Parameters (current year & month)
DECLARE #pYear SMALLINT = 2013,
#pMonth TINYINT = 1;
DECLARE #FirstDayOfCurrentMonth DATE = CONVERT(DATE, CONVERT(CHAR(4), #pYear) + '-' + CONVERT(CHAR(2), #pMonth) + '-01');
DECLARE #StartDate DATE = DATEADD(MONTH, -1, #FirstDayOfCurrentMonth), -- Begining of the previous month
#EndDate DATE = DATEADD(DAY, -1, DATEADD(MONTH, 1, #FirstDayOfCurrentMonth)) -- End of the current month
SELECT TOP(3) t.ItemID,
t.[2]-t.[1] AS IncreaseAmount
FROM
(
SELECT y.ItemID, y.Amount,
DENSE_RANK() OVER(ORDER BY y.FirstDayOfSalesMonth ASC) AS MonthNum -- 1=Previous Month, 2=Current Month
FROM
(
SELECT x.ItemID, x.Amount,
DATEADD(MONTH, DATEDIFF(MONTH, 0, x.SalesDate), 0) AS FirstDayOfSalesMonth
FROM #Sales x
WHERE x.SalesDate BETWEEN #StartDate AND #EndDate
) y
) z
PIVOT( SUM(z.Amount) FOR z.MonthNum IN ([1], [2]) ) t
ORDER BY IncreaseAmount DESC;
SQLFiddle demo
Your sample data seems to be incomplete, however, here is my try. I assume that you want to know the three items with the greatest sales-difference from one month to the next:
WITH Increases AS
(
SELECT a1.itemid,
a1.sales - (SELECT a2.sales
FROM dbo.abc a2
WHERE a1.itemid = a2.itemid
AND ( ( a1.year = a2.year
AND a1.month > 1
AND a1.month = a2.month + 1 )
OR ( a1.year = a2.year + 1
AND a1.month = 1
AND a2.month = 12 ) ))AS IncreaseInSales
FROM dbo.abc a1
)
SELECT TOP 3 ItemID, MAX(IncreaseInSales) AS IncreaseInSales
FROM Increases
GROUP BY ItemID
ORDER BY MAX(IncreaseInSales) DESC
Demo
SELECT
cur.[ItemId]
MAX(nxt.[Sales] - cur.[Sales]) AS [IncreaseInSales]
FROM ABC cur
INNER JOIN ABC nxt ON (
nxt.[Year] = cur.[Year] + cur.[month]/12 AND
nxt.[Month] = cur.[Month]%12 + 1
)
GROUP BY cur.[ItemId]
I'd do this this way. It should work in all the tagged versions of SQL Server:
SELECT TOP 3 [ItemId],
MAX(CASE WHEN [Month] = 2 THEN [Sales] END) -
MAX(CASE WHEN [Month] = 1 THEN [Sales] END) [Diff]
FROM t
WHERE [Month] IN (1, 2) AND [Year] = 2013
GROUP BY [ItemId]
HAVING COUNT(*) = 2
ORDER BY [Diff] DESC
Fiddle here.
The reason why I'm adding the HAVING clause is that if any item is added in only one of the months then the numbers will be all wrong. So I'm only comparing items that are only present in both months.
The reason of the WHERE clause would be to filter in advance only the needed months and improve the efficiency of the query.
An SQL Server 2012 solution could also be:
SELECT TOP 3 [ItemId], [Diff] FROM (
SELECT [ItemId],
LEAD([Sales]) OVER (PARTITION BY [ItemId] ORDER BY [Month]) - [Sales] Diff
FROM t
WHERE [Month] IN (1, 2) AND [Year] = 2013
) s
WHERE [Diff] IS NOT NULL
ORDER BY [Diff] DESC
I have my sql tables and query as shown below :
CREATE TABLE #ABC([Year] INT, [Month] INT, Stores INT);
CREATE TABLE #DEF([Year] INT, [Month] INT, SalesStores INT);
CREATE TABLE #GHI([Year] INT, [Month] INT, Products INT);
INSERT #ABC VALUES (2013,1,1);
INSERT #ABC VALUES (2013,1,2);
INSERT #ABC VALUES (2013,2,3);
INSERT #DEF VALUES (2013,1,4);
INSERT #DEF VALUES (2013,1,5);
INSERT #DEF VALUES (2013,2,6);
INSERT #GHI VALUES (2013,1,7);
INSERT #GHI VALUES (2013,1,8);
INSERT #GHI VALUES (2013,2,9);
INSERT #GHI VALUES (2013,3,10);
My current query is
SELECT T.[Year],
T.[Month]
-- select the sum for each year/month combination using a correlated subquery (each result from the main query causes another data retrieval operation to be run)
,
(SELECT SUM(Stores)
FROM #ABC
WHERE [Year] = T.[Year]
AND [Month] = T.[Month]) AS [Sum_Stores],
(SELECT SUM(SalesStores)
FROM #DEF
WHERE [Year] = T.[Year]
AND [Month] = T.[Month]) AS [Sum_SalesStores],
(SELECT SUM(Products)
FROM #GHI
WHERE [Year] = T.[Year]
AND [Month] = T.[Month]) AS [Sum_Products]
FROM (
-- this selects a list of all possible dates.
SELECT [Year],
[Month]
FROM #ABC
UNION
SELECT [Year],
[Month]
FROM #DEF
UNION
SELECT [Year],
[Month]
FROM #GHI) AS T;
Which returns
+------+-------+------------+-----------------+--------------+
| Year | Month | Sum_Stores | Sum_SalesStores | Sum_Products |
+------+-------+------------+-----------------+--------------+
| 2013 | 1 | 3 | 9 | 15 |
| 2013 | 2 | 3 | 6 | 9 |
| 2013 | 3 | NULL | NULL | 10 |
+------+-------+------------+-----------------+--------------+
What I want to do is to add two more columns to my query which shows
Sum_SalesStores/Sum_Products & Sum_SalesStores/Sum_Stores per each month and then sort the query based on the two expressions. Can anyone tell me how its possible ?
One way would just be to chuck your entire existing query into a CTE then you can select from that and perform the calculations.
;WITH CTE
AS (
/*Paste your existing query*/
)
SELECT *,
Sum_SalesStores / Sum_Products AS Foo,
Sum_SalesStores / Sum_Stores AS Bar
FROM CTE
ORDER BY Foo,
Bar
I re-factored your code a bit to place the core of the logic in the FROM statement.
SELECT Dates.[Year]
,Dates.[Month]
,SumStores
,SumSalesStores
,SumProducts
,SumSalesStores/SumProducts
,SumSalesStores/SumStores
FROM
(
-- This selects a list of all possible dates.
SELECT [Year],[Month] FROM ABC
UNION SELECT [Year],[Month] FROM DEF
UNION SELECT [Year],[Month] FROM GHI
) AS Dates
Left Join
(
SELECT [Year]
,[Month]
,SumStores = Sum(Stores)
FROM ABC
GROUP BY [Year]
,[Month]
) As Stores
On Dates.[Year] = Stores.[Year]
And Dates.[Month] = Stores.[Month]
Left Join
(
SELECT [Year]
,[Month]
,SumSalesStores = Sum(SalesStores)
FROM DEF
GROUP BY [Year]
,[Month]
) As SalesStores
On Dates.[Year] = SalesStores.[Year]
And Dates.[Month] = SalesStores.[Month]
Left Join
(
SELECT [Year]
,[Month]
,SumProducts = Sum(Products)
FROM GHI
GROUP BY [Year]
,[Month]
) As Products
On Dates.[Year] = Products.[Year]
And Dates.[Month] = Products.[Month]
ORDER BY 1, 2
Here's the SQL Fiddle.
I am having scenario like this : I am having many tables and each table has date fields.
Table: FA
Id | Created_Date |
------------------------
1 | 1/12/2012 |
2 | 2/15/2012 |
3 | 2/25/2012 |
Table: TPA
Id | Created_Date |
------------------------
1 | 3/10/2012 |
2 | 4/25/2012 |
3 | 5/20/2012 |
4 | 5/21/2012 |
Table: Gift
Id | Created_Date |
------------------------
1 | 6/10/2012 |
2 | 7/25/2012 |
3 | 8/10/2012 |
3 | 7/11/2012 |
I want output like I want total count of records from each table and display it respective to month wise by using Created_Date field dates.
Expected Output like this:
Give this solution a try,
SELECT MonthName,
COALESCE(FA, 0) FA,
COALESCE(TPA, 0) TPA,
COALESCE(GIFT, 0) GIFT
FROM
(
SELECT monthList.ordby,
monthList.MonthName,
org.TableName,
org.TotalCount
FROM
(
SELECT 1 ordby, 'January' MonthName UNION SELECT 2, 'February' UNION
SELECT 3, 'March' UNION SELECT 4, 'April' UNION
SELECT 5,'May' UNION SELECT 6,'June' UNION
SELECT 7,'July' UNION SELECT 8,'August' UNION
SELECT 9,'September' UNION SELECT 10,'October' UNION
SELECT 11,'November' UNION SELECT 12,'December'
) monthList
LEFT JOIN
(
SELECT 'FA' TableName,
DATENAME(mm,Created_Date) MonthName,
COUNT(*) TotalCount
FROM FA
GROUP BY DATENAME(mm,Created_Date)
UNION
SELECT 'TPA' TableName,
DATENAME(mm,Created_Date) MonthName,
COUNT(*) TotalCount
FROM TPA
GROUP BY DATENAME(mm,Created_Date)
UNION
SELECT 'Gift' TableName,
DATENAME(mm,Created_Date) MonthName,
COUNT(*) TotalCount
FROM Gift
GROUP BY DATENAME(mm,Created_Date)
) org ON monthList.MonthName = org.MonthName
) data
PIVOT
(
MAX(TotalCount)
FOR TableName IN ([FA], [TPA],[GIFT])
) head
ORDER BY ordby
http://www.sqlfiddle.com/#!3/dc613/14
I was trying to get the Find the solution since last 4 Hours
I think my answer is Low in Performance as Compare to above Answer,
create table #month
(
id [int] IDENTITY(1,1) NOT NULL,
[month] varchar(3)
)
DBCC CHECKIDENT(#month, RESEED, 1)
insert into #month
values
('Jan'),
('Feb'),
('Mar'),
('Apr'),
('May'),
('Jun'),
('Jul'),
('Aug'),
('Sep'),
('Oct'),
('Nov'),
('Dec')
declare #id int
set #id=1
declare #month varchar(3)
declare #sql nvarchar(max)
set #sql=''
declare #order varchar(3)
while (#id<13)
BEGIN
set #month=(select [month] from #month where id=#id)
set #order=CONVERT(varchar(3),#id)
set #sql=#sql+'insert into #display
(
[Month],
[COUNT(FA)],
[COUNT(TPA)],
[COUNT(Gift)],
[ORDER]
)
select '''+ #month +''' AS [Month],
(select
COUNT(CONVERT(VARCHAR(3), DATENAME(MM,Created_Date), 100))
from FA
where CONVERT(VARCHAR(3), DATENAME(MM,Created_Date), 100)='''+ #month +''') [COUNT(FA)],
(select
COUNT(CONVERT(VARCHAR(3), DATENAME(MM,Created_Date), 100))
from TPA
where CONVERT(VARCHAR(3), DATENAME(MM,Created_Date), 100)='''+ #month +''') [COUNT(TPA)],
(select
COUNT(CONVERT(VARCHAR(3), DATENAME(MM,Created_Date), 100))
from Gift
where CONVERT(VARCHAR(3), DATENAME(MM,Created_Date), 100)='''+ #month +''') [COUNT(Gift)],
'''+ #order + ''' [Order]
'
set #id=#id+1 --Incrementing the month
END
exec sp_executesql #sql
print #sql
select [MONTH],
[COUNT(FA)],
[COUNT(TPA)],
[COUNT(Gift)]
from #display
order by convert(int,[ORDER])