This question already has an answer here:
Closed 12 years ago.
Possible Duplicate:
How to join two tables
table 1
Date StartingAum
07/01/2010 120
08/01/2010 220
09/01/2010 320
table 2
Date DepContr withdra
01/01/2010 60 15
02/01/2010 70 25
03/01/2010 80 15
04/01/2010 30 89
05/01/2010 40 15
06/01/2010 25 85
07/01/2010 16 17
08/01/2010 19 21
09/01/2010 68 79
the output should be
Date StartingAum DepContr withdra
01/01/2010 0 60 15
02/01/2010 0 70 25
03/01/2010 0 80 15
04/01/2010 0 30 89
05/01/2010 0 40 15
06/01/2010 0 25 85
07/01/2010 120 16 17
08/01/2010 220 19 21
09/01/2010 320 68 79
i need the output exactly similar to that
DECLARE #Table1 table ([date] datetime, StartingAum int)
DECLARE #Table2 table ([date] datetime, DepContr int, withdra int)
INSERT #Table1 VALUES ('07/01/2010', 120)
INSERT #Table1 VALUES ('08/01/2010', 220)
INSERT #Table1 VALUES ('09/01/2010', 320)
INSERT #Table2 VALUES ('01/01/2010', 60 , 15)
INSERT #Table2 VALUES ('02/01/2010', 70 , 25)
INSERT #Table2 VALUES ('03/01/2010', 80 , 15)
INSERT #Table2 VALUES ('04/01/2010', 30 , 89)
INSERT #Table2 VALUES ('05/01/2010', 40 , 15)
INSERT #Table2 VALUES ('06/01/2010', 25 , 85)
INSERT #Table2 VALUES ('07/01/2010', 16 , 17)
INSERT #Table2 VALUES ('08/01/2010', 19 , 21)
INSERT #Table2 VALUES ('09/01/2010', 68 , 79)
SELECT
t2.[Date]
,ISNULL(t1.StartingAum, 0) AS StartingAum
,t2.DepContr
,t2.withdra
FROM #Table2 t2
LEFT JOIN #Table1 t1 ON t2.[Date] = t1.[Date]
ORDER BY t2.[Date]
OUTPUT:
Date StartingAum DepContr withdra
----------------------- ----------- ----------- -----------
2010-01-01 00:00:00.000 0 60 15
2010-02-01 00:00:00.000 0 70 25
2010-03-01 00:00:00.000 0 80 15
2010-04-01 00:00:00.000 0 30 89
2010-05-01 00:00:00.000 0 40 15
2010-06-01 00:00:00.000 0 25 85
2010-07-01 00:00:00.000 120 16 17
2010-08-01 00:00:00.000 220 19 21
2010-09-01 00:00:00.000 320 68 79
I think you should have a look at this page: http://www.w3schools.com/sql/sql_union.asp
That might be helpful?
Related
I have data like this in a table:
https://i.stack.imgur.com/JYZjz.png
I want to group first two events (1, 10) as F1, than second two events (1,10) as F2
Running this SQL query:
SELECT
Id, Date, Event,
CASE
WHEN Event = 1 AND LEAD(Event) OVER (ORDER BY ID) = 10
THEN 'F1'
WHEN Event = 10 AND LAG(Event) OVER (ORDER BY ID) = 1
THEN 'F1'
ELSE NULL
END AS Flow
FROM
lxfr.SystemEventsDiary
WHERE
Event IN (1, 10)
I get this result as output:
ID
Date
Event
Flow
4
2022-02-07 00:00:00.000
1
F1
44
2022-02-08 00:00:00.000
10
F1
47
2022-02-09 00:00:00.000
1
F1
72
2022-02-10 00:00:00.000
10
F1
75
2022-02-10 00:00:00.000
1
F1
97
2022-02-11 00:00:00.000
10
F1
100
2022-02-11 00:00:00.000
1
NULL
113
2022-02-28 00:00:00.000
1
F1
217
2022-03-04 00:00:00.000
10
F1
235
2022-03-22 00:00:00.000
10
NULL
241
2022-03-22 00:00:00.000
1
F1
270
2022-03-24 00:00:00.000
10
F1
273
2022-03-24 00:00:00.000
1
F1
308
2022-03-25 00:00:00.000
10
F1
But I need a result like this:
ID
Date
Event
Flow
4
2022-02-07 00:00:00.000
1
F1
44
2022-02-08 00:00:00.000
10
F1
47
2022-02-09 00:00:00.000
1
F2
72
2022-02-10 00:00:00.000
10
F2
75
2022-02-10 00:00:00.000
1
F3
97
2022-02-11 00:00:00.000
10
F3
100
2022-02-11 00:00:00.000
1
NULL
113
2022-02-28 00:00:00.000
1
F4
217
2022-03-04 00:00:00.000
10
F4
235
2022-03-22 00:00:00.000
10
NULL
241
2022-03-22 00:00:00.000
1
F5
270
2022-03-24 00:00:00.000
10
F5
273
2022-03-24 00:00:00.000
1
F6
308
2022-03-25 00:00:00.000
10
F6
I tried with a CTE, but I'm getting errors...
Thanks
This seems to work. I've copied your desired output as my input sample data just to show that my new column matches your Desired one, and also a couple of other renames for keywords:
declare #t table (ID int, DateOf datetime, EventNo int, DesiredFlow varchar(7))
insert into #t(ID,DateOf,EventNo,DesiredFlow) values
(4 ,'2022-02-07T00:00:00.000',1 ,'F1'),
(44 ,'2022-02-08T00:00:00.000',10 ,'F1'),
(47 ,'2022-02-09T00:00:00.000',1 ,'F2'),
(72 ,'2022-02-10T00:00:00.000',10 ,'F2'),
(75 ,'2022-02-10T00:00:00.000',1 ,'F3'),
(97 ,'2022-02-11T00:00:00.000',10 ,'F3'),
(100 ,'2022-02-11T00:00:00.000',1 ,NULL),
(113 ,'2022-02-28T00:00:00.000',1 ,'F4'),
(217 ,'2022-03-04T00:00:00.000',10 ,'F4'),
(235 ,'2022-03-22T00:00:00.000',10 ,NULL),
(241 ,'2022-03-22T00:00:00.000',1 ,'F5'),
(270 ,'2022-03-24T00:00:00.000',10 ,'F5'),
(273 ,'2022-03-24T00:00:00.000',1 ,'F6'),
(308 ,'2022-03-25T00:00:00.000',10 ,'F6')
;With Neighbours as (
select
*,
LEAD(EventNo,1,NULL) OVER (ORDER BY ID) as Successor,
LAG(EventNo,1,NULL) OVER (ORDER BY ID) as Predecessor
from
#t t
), NoStragglers as (
select
*
from
Neighbours
where
(EventNo = 1 and Successor = 10) or
(EventNo = 10 and Predecessor = 1)
), Ordered as (
select
*, ROW_NUMBER() OVER (PARTITION BY EventNo ORDER BY ID) as rn
from NoStragglers
)
select
t.*,'F' + (CONVERT(varchar(10),o.rn)) as ActualFlow
from
#t t
left join
Ordered o
on
t.Id = o.Id
Hopefully you can see how each CTE builds from the previous one (either by inspection or changing the final select to pull one one of the earlier CTEs instead).
Result:
ID DateOf EventNo DesiredFlow ActualFlow
----------- ----------------------- ----------- ----------- -----------
4 2022-02-07 00:00:00.000 1 F1 F1
44 2022-02-08 00:00:00.000 10 F1 F1
47 2022-02-09 00:00:00.000 1 F2 F2
72 2022-02-10 00:00:00.000 10 F2 F2
75 2022-02-10 00:00:00.000 1 F3 F3
97 2022-02-11 00:00:00.000 10 F3 F3
100 2022-02-11 00:00:00.000 1 NULL NULL
113 2022-02-28 00:00:00.000 1 F4 F4
217 2022-03-04 00:00:00.000 10 F4 F4
235 2022-03-22 00:00:00.000 10 NULL NULL
241 2022-03-22 00:00:00.000 1 F5 F5
270 2022-03-24 00:00:00.000 10 F5 F5
273 2022-03-24 00:00:00.000 1 F6 F6
308 2022-03-25 00:00:00.000 10 F6 F6
Which seems to match.
Check this,
create table #temp(id int,dates datetime,Events int)
insert into #temp(id,dates,events) values
(4 ,'2022-02-07 00:00:00.000', 1 )
,(44 ,'2022-02-08 00:00:00.000', 10 )
,(47 ,'2022-02-09 00:00:00.000', 1 )
,(72 ,'2022-02-10 00:00:00.000', 10 )
,(75 ,'2022-02-10 00:00:00.000', 1 )
,(97 ,'2022-02-11 00:00:00.000', 10 )
,(100 ,'2022-02-11 00:00:00.000', 1 )
,(113 ,'2022-02-28 00:00:00.000', 1 )
,(217 ,'2022-03-04 00:00:00.000', 10 )
,(235 ,'2022-03-22 00:00:00.000', 10 )
,(241 ,'2022-03-22 00:00:00.000', 1 )
,(270 ,'2022-03-24 00:00:00.000', 10 )
,(273 ,'2022-03-24 00:00:00.000', 1 )
,(308 ,'2022-03-25 00:00:00.000', 10 )
WITH CTE
AS (SELECT Id,
Dates,
Events,
CASE
WHEN Events = 1
AND LEAD(Events) OVER(
ORDER BY ID) = 10
THEN id
WHEN Events = 10
AND LAG(Events) OVER(
ORDER BY ID) = 1
THEN LAG(id) OVER(
ORDER BY ID)
ELSE NULL
END AS Flow
FROM #temp),
CtE1
AS (SELECT *,
DENSE_RANK() OVER(
ORDER BY flow) rn
FROM CTe
WHERE flow IS NOT NULL
UNION ALL
SELECT *,
NULL
FROM CTE
WHERE flow IS NULL)
SELECT id,
dates,
events,
CASE
WHEN rn IS NOT NULL
THEN concat('F', rn)
ELSE NULL
END Flow
FROM cte1
ORDER BY id;
drop table #temp
You can use cascading subqueries to assign a ROW_NUMBER() based on Flow values that are NOT NULL:
SELECT d.Id,
d.Date,
d.Event,
CASE WHEN b.rn IS NULL THEN NULL
ELSE CONCAT('F', b.rn)
END AS Flow
FROM (SELECT
Id,
Date,
Event,
Flow,
ROW_NUMBER() OVER (PARTITION BY Event ORDER BY Id ASC) as rn
FROM (SELECT
Id,
Date,
Event,
CASE WHEN Event = 1 AND LEAD(Event) OVER (ORDER BY Id) = 10 THEN 1
WHEN Event = 10 AND LAG(Event) OVER (ORDER BY Id) = 1 THEN 1
ELSE 0
END as Flow
FROM SystemEventsDiary WHERE Event IN (1, 10)
) a WHERE Flow = 1) b
RIGHT JOIN SystemEventsDiary d ON b.id = d.Id
ORDER BY d.Id ASC
Result:
Id
Date
Event
Flow
4
2022-02-07 00:00:00.000
1
F1
44
2022-02-08 00:00:00.000
10
F1
47
2022-02-09 00:00:00.000
1
F2
72
2022-02-10 00:00:00.000
10
F2
75
2022-02-10 00:00:00.000
1
F3
97
2022-02-11 00:00:00.000
10
F3
100
2022-02-11 00:00:00.000
1
NULL
113
2022-02-28 00:00:00.000
1
F4
217
2022-03-04 00:00:00.000
10
F4
235
2022-03-22 00:00:00.000
10
NULL
241
2022-03-22 00:00:00.000
1
F5
270
2022-03-24 00:00:00.000
10
F5
273
2022-03-24 00:00:00.000
1
F6
308
2022-03-25 00:00:00.000
10
F6
db<>fiddle here.
First I'm using AdventureWork2019 as a reference
I have a query where I'm joining 5 Tables
USE [AdventureWorks2019]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
Alter PROCEDURE dbo.TestLocation
#UseDate DateTime
AS
BEGIN
SET NOCOUNT ON;
SELECT prodID
,SUM(PurchQty) AS TotalPurchase
,SUM(SalesQty) AS TotalSell
,StartDate
from (
SELECT DISTINCT WO.ProductID AS prodID
, StartDate
,WO.OrderQty AS PurchQty
,SOD.OrderQty AS SalesQty
FROM Sales.SalesOrderDetail SOD
LEFT JOIN Production.WorkOrderRouting WOR ON WOR.ProductID = SOD.ProductID
--LEFT JOIN Production.Location PL ON PL.LocationID = WOR.LocationID
--The above Join is the one for the locationID and it's working Fine
LEFT JOIN Production.WorkOrder WO ON WO.ProductID = SOD.ProductID
FULL OUTER JOIN Purchasing.PurchaseOrderDetail POD ON POD.ProductID = SOD.ProductID
WHERE StartDate = #UseDate
-- AND PL.LocationID >= 10
) Test3
Group by prodID,StartDate
order by prodID ASC, StartDate
END
GO
EXEC TestLocation '2011-07-02 00:00:00.000'
Output(sample):
prodID TotalPurc TotalSell StartDate
717 8 36 2011-07-02 00:00:00.000
730 9 47 2011-07-02 00:00:00.000
744 2 3 2011-07-02 00:00:00.000
747 12 21 2011-07-02 00:00:00.000
749 5 15 2011-07-02 00:00:00.000
761 16 138 2011-07-02 00:00:00.000
775 26 91 2011-07-02 00:00:00.000
777 12 78 2011-07-02 00:00:00.000
802 6 21 2011-07-02 00:00:00.000
804 40 60 2011-07-02 00:00:00.000
806 16 138 2011-07-02 00:00:00.000
807 24 23 2011-07-02 00:00:00.000
810 21 28 2011-07-02 00:00:00.000
811 6 21 2011-07-02 00:00:00.000
813 8 37 2011-07-02 00:00:00.000
817 21 28 2011-07-02 00:00:00.000
And another Table For LocationID (as a warehouse)
SELECT LocationID,CostRate,Availability
FROM Production.Location
WHERE LocationID >= 10
order by CostRate ASC
LocationID CostRate Availability
50 12.25 120.00
60 12.25 120.00
30 14.50 120.00
40 15.75 120.00
45 18.00 80.00
10 22.50 96.00
20 25.00 108.00
What I want to do is to take each LoactionId and ProdID and take TotalPurc to the location and decrement the quantity in the Availability column, each TotalSell will increment the Availability column. The max Availability quantity is 130.
If all locations have no Available quantity that is the Available is 0 for all locations then it will stop.
the above will work with the date specified as you can check the query and run it if you have
AdventureWork2019
simple output to check how I want the data to be:
prodID TotalPurc TotalSell StartDate
717 8 36 2011-07-02 00:00:00.000
730 9 47 2011-07-02 00:00:00.000
744 2 3 2011-07-02 00:00:00.000
747 12 21 2011-07-02 00:00:00.000
749 5 15 2011-07-02 00:00:00.000
LocationID CostRate Availability
50 12.25 120.00
60 12.25 120.00
30 14.50 120.00
40 15.75 120.00
45 18.00 80.00
10 22.50 96.00
20 25.00 108.00
Output :
prodID TotalPurc TotalSell StartDate LocationID Availability Remaining
717 8 36 2011-07-02 00:00:00.000 50 130 18
717 8 36 2011-07-02 00:00:00.000 60 130 8
717 8 36 2011-07-02 00:00:00.000 30 128 0
--what happened above is that I took the (120-8) = 112 then 112+36 = 148 we only can use 130 then the remaining is 18 then we took the next `LocationID` with the least Cost (120+18 = 138 we can use 130 so we took the 8) and used it in the next `LocationID`
730 9 47 2011-07-02 00:00:00.000 30 130 36
730 9 47 2011-07-02 00:00:00.000 40 130 26
730 9 47 2011-07-02 00:00:00.000 45 106 0
744 2 3 2011-07-02 00:00:00.000 45 107 0
747 12 21 2011-07-02 00:00:00.000 45 116 0
749 5 15 2011-07-02 00:00:00.000 45 126 0
--the above is the same as the first 3 rows we subtract and add to the availability
The other condition is that if all locations reached 0 or 130 then stop
How can I do that in SQL Server? I tried using CTE but didn't work well with me and tried the cursor which I think is the best for this kind of thing but didn't achieve anything.
Thank you in advance
Edit :
ALTER FUNCTION GetStockMovment
(
-- Add the parameters for the function here
#ForDate Datetime
)
RETURNS #Sums TABLE (
RemoveQTY Numeric(24, 7),
ADDQTY Numeric(24, 7)
)
AS
BEGIN
Declare #WoSum Numeric(24, 7),
#SODSUM Numeric(24, 7),
#WORSum Numeric(24, 7),
#PODSum Numeric(24, 7)
select #SODSUM = SUM(SOD.OrderQty) from Sales.SalesOrderDetail SOD
INNER JOIN Sales.SalesOrderHeader SOH ON SOD.SalesOrderID = SOH.SalesOrderID
where SOH.OrderDate = #ForDate
select #WoSum = sum(orderQty) from Production.WorkOrder
where StartDate = #ForDate
select #PODSum = sum(POD.OrderQty) from Purchasing.PurchaseOrderDetail POD
INNER JOIN Purchasing.PurchaseOrderHeader POH ON POD.PurchaseOrderID = POH.PurchaseOrderID
where POH.OrderDate = #ForDate
select #WoSum = sum(WO.OrderQty) from Production.WorkOrder WO
where WO.DueDate = #ForDate
INSERT INTO #Sums (RemoveQTY,ADDQTY)
SELECT isnull(#SODSUM,0) + isnull(#WORSum,0) , isnull(#PODSum,0) + isnull(#WoSum,0)
RETURN;
END;
GO
select * from dbo.GetStockMovment ('2014-05-26 00:00:00.000')
Output:
RemoveQTY ADDQTY
189.0000000 5334.0000000
You should use LAG or LEAD function.
https://learn.microsoft.com/en-us/sql/t-sql/functions/lead-transact-sql?view=sql-server-ver15
https://learn.microsoft.com/en-us/sql/t-sql/functions/lag-transact-sql?view=sql-server-ver15
I have working SQL Server.I have More than 20000 Lines Using SQL server.I have column Filed Name Amount. in Amount Filed Inserted negative and Positive Number .Now I want Sort Amount Field Negative and Positive Number
Example Like :
Entity ExpenseTypeCode ExpenseType Amount
11 043 Hotel 5
12 044 travel 23
13 045 drink 55
14 046 Dinner 23
15 047 airline 556
16 048 Hotel -5
I how Like More than 30000 LINES .IN my table i have Expense type but negative and Positive value
I want Sort My table Like negative and Positive order same value
Entity ExpenseTypeCode ExpenseType Amount
11 043 Hotel 5
16 048 Hotel -5 --> Want sort like this
12 044 travel 23
13 045 drink 55
14 046 Dinner 23
15 047 airline 556
How can i sort my table liKE ?
Use ABS Function in sorting:
ABS() : It will convert your negative value to positive
SELECT
*
FROM TableName
Order BY ABS(Amount)
If you wants if negative and positive value same and order should consider positive first then:
SELECT
*
FROM TableName
Order BY ABS(Amount),Amount*-1
Example:
Initial
Output
select * from #t t
order by expensetype,
case when amount > 0 then 1 else 2 end
result
Entity ExpenseTypeCode ExpenseType Amount
----------- --------------- ----------- -----------
15 47 airline 556
14 46 Dinner 23
13 45 drink 55
11 43 Hotel 5
16 48 Hotel -5
12 44 travel 23
If you are looking for matching pairs then something like this might be what you want
declare #t table(Entity int, ExpenseTypeCode int, ExpenseType varchar(10), Amount int)
insert into #t values
( 11, 043, 'Hotel' , 6),
( 8, 043, 'Hotel' , 5),
( 9, 043, 'Hotel' , 5),
( 10, 043, 'Hotel' , 5),
( 12, 044, 'travel' , 23),
( 13, 045, 'drink' , 55),
( 14, 046, 'Dinner' , 23),
( 15, 047, 'airline' , 556),
( 16, 048, 'Hotel' , -5),
( 17, 048, 'Hotel' , -5),
( 18, 043, 'Hotel' , -6),
( 19, 043, 'Hotel' , -6)
select t.*,row_number() over(partition by t.ExpenseType, t.amount order by t.entity) rn,t.amount as absamount
from #t t
where t.amount > 0
union all
select t.*,row_number() over(partition by t.ExpenseTypeCode, t.amount order by t.entity) rn, abs(t.amount)
from #t t
where t.amount < 0
order by t.expensetype,absamount,rn,t.amount desc
result
Entity ExpenseTypeCode ExpenseType Amount rn absamount
----------- --------------- ----------- ----------- -------------------- -----------
15 47 airline 556 1 556
14 46 Dinner 23 1 23
13 45 drink 55 1 55
8 43 Hotel 5 1 5
16 48 Hotel -5 1 5
9 43 Hotel 5 2 5
17 48 Hotel -5 2 5
10 43 Hotel 5 3 5
11 43 Hotel 6 1 6
18 43 Hotel -6 1 6
19 43 Hotel -6 2 6
12 44 travel 23 1 23
or possibly a full join
select s.*,t.* from
(
select t.*,row_number() over(partition by t.ExpenseType, t.amount order by t.entity) rn
from #t t
where t.amount > 0
) s
full join
(
select t.*,row_number() over(partition by t.ExpenseTypeCode, t.amount order by t.entity) rn
from #t t
where t.amount < 0
) t on t.expensetype = s.expensetype and t.rn = s.rn and abs(t.amount) = s.amount
order by s.expensetype
Entity ExpenseTypeCode ExpenseType Amount rn Entity ExpenseTypeCode ExpenseType Amount rn
----------- --------------- ----------- ----------- -------------------- ----------- --------------- ----------- ----------- --------------------
NULL NULL NULL NULL NULL 19 43 Hotel -6 2
15 47 airline 556 1 NULL NULL NULL NULL NULL
14 46 Dinner 23 1 NULL NULL NULL NULL NULL
13 45 drink 55 1 NULL NULL NULL NULL NULL
11 43 Hotel 6 1 18 43 Hotel -6 1
10 43 Hotel 5 3 NULL NULL NULL NULL NULL
8 43 Hotel 5 1 16 48 Hotel -5 1
9 43 Hotel 5 2 17 48 Hotel -5 2
12 44 travel 23 1 NULL NULL NULL NULL NULL
Can anybody help me out to do this:
My table data is like
Datefiled Field1 Field2 Field2 Field4
01-01-2012 ABC 10 15 17
01-04-2013 PQR 7 80 65
01-05-2014 XYZ 15 25 77
The output would look something like this
Month/Year Field1 Field2 Field2 Field4
01/2012 ABC 10 15 17
02/2012 ABC 10 15 17
03/2012 ABC 10 15 17
04/2012 ABC 10 15 17
.....
03/2013 ABC 10 15 17
04/2013 PQR 7 80 65
05/2013 PQR 7 80 65
06/2013 PQR 7 80 65
07/2013 PQR 7 80 65
.......
04/2014 PQR 7 80 65
05/2014 XYZ 15 25 77
Just create a calendar table, either one row per day or one row per month, and you can use a tally table (=virtual, constructed for example with a CTE) too and do something like this:
select
*
from
calendar c
cross apply (
select top 1 *
from yourtable y
where y.Datefiled < c.calendardate
order by Datefiled desc
) y
;WITH datat as (
SELECT *
FROM (VALUES
('2012-01-01', 'ABC', 10, 15, 17),('2012-12-12', 'LKJ', 16, 12, 13),
('2013-01-15', 'CVB', 16, 11, 19),('2013-04-01', 'PQR', 7, 80, 65),
('2014-04-24', 'XYZ', 15, 25, 77),('2014-05-17', 'DEF', 12, 40, 50)
) as t(Datefiled, Field1, Field2, Field3, Field4)
), cte AS (
SELECT CAST(MIN(Datefiled) AS DATE) as date_,
CAST(MAX(Datefiled) AS DATE) AS maxd
FROM datat
UNION ALL
SELECT DATEADD(day,1,date_), maxd
FROM cte
WHERE date_ < maxd
)
SELECT CAST([Month] as nvarchar(2)) + '/' + CAST([Year] as nvarchar(4)) as [Month/Year],
Field1,
Field2,
Field3,
Field4
FROM (
SELECT DISTINCT
MONTH(date_) as [Month],
YEAR(date_) as [Year],
Field1,
Field2,
Field3,
Field4
FROM cte c
LEFT JOIN (
SELECT TOP 1 WITH TIES CAST(DATEADD(MONTH, DATEDIFF(MONTH, 0, d1.Datefiled ), 0) as date) as [DateStart],
CAST(DATEADD(MILLISECOND, -3, DATEADD(MONTH, DATEDIFF(MONTH, 0, d2.Datefiled), 0)) as date) as [DateEnd],
d1.Field1,
d1.Field2,
d1.Field3,
d1.Field4
FROM datat d1
LEFT JOIN datat d2
ON d1.Datefiled < d2.Datefiled
ORDER BY ROW_NUMBER() OVER (PARTITION BY d1.Datefiled ORDER BY d2.Datefiled)
) as d
ON c.date_ between d.[DateStart] and ISNULL(d.[DateEnd],c.date_)
WHERE Field1 IS NOT NULL
) as t
ORDER BY [Year], [Month]
OPTION (MAXRECURSION 0)
Output:
Month/Year Field1 Field2 Field3 Field4
---------- ------ ----------- ----------- -----------
1/2012 ABC 10 15 17
2/2012 ABC 10 15 17
3/2012 ABC 10 15 17
4/2012 ABC 10 15 17
5/2012 ABC 10 15 17
6/2012 ABC 10 15 17
7/2012 ABC 10 15 17
8/2012 ABC 10 15 17
9/2012 ABC 10 15 17
10/2012 ABC 10 15 17
11/2012 ABC 10 15 17
12/2012 LKJ 16 12 13
1/2013 CVB 16 11 19
2/2013 CVB 16 11 19
3/2013 CVB 16 11 19
4/2013 PQR 7 80 65
5/2013 PQR 7 80 65
6/2013 PQR 7 80 65
7/2013 PQR 7 80 65
8/2013 PQR 7 80 65
9/2013 PQR 7 80 65
10/2013 PQR 7 80 65
11/2013 PQR 7 80 65
12/2013 PQR 7 80 65
1/2014 PQR 7 80 65
2/2014 PQR 7 80 65
3/2014 PQR 7 80 65
4/2014 XYZ 15 25 77
5/2014 DEF 12 40 50
(29 row(s) affected)
I have a table that lists visits to a clinic. I'd like to get a "histogram" of sorts showing how frequently patients visit the clinic along with totals. Here's some sample code (tested under MS SQL Server 2005) to show what I'm talking about:
CREATE TABLE #test (
visit_id int IDENTITY(1,1),
patient_id int
);
DECLARE #num_patients int;
SELECT #num_patients = 1000 + ABS(CHECKSUM(NEWID())) % 250;
INSERT INTO #test (patient_id)
SELECT TOP 15 PERCENT ABS(CHECKSUM(NEWID())) % #num_patients
FROM sysobjects a, sysobjects b;
-- SELECT COUNT(*) AS total_visits FROM #test;
-- SELECT COUNT(DISTINCT patient_id) AS distinct_patients FROM #test;
SELECT CASE GROUPING(num_pat_visits) WHEN 1 THEN 'Total'
ELSE CAST(num_pat_visits AS varchar(5)) END AS num_pat_visits,
COUNT(*) AS num_patients, num_pat_visits * COUNT(*) AS tot_pat_visit
FROM
(SELECT patient_id, COUNT(*) AS num_pat_visits FROM #test GROUP BY patient_id) a
GROUP BY num_pat_visits WITH ROLLUP
ORDER BY CAST(num_pat_visits AS int) DESC;
This gets me almost to where I want:
num_pat_visits num_patients tot_pat_visit
-------------- ------------ -------------
60 1 60
54 2 108
52 2 104
51 4 204
50 3 150
49 3 147
48 7 336
47 7 329
46 15 690
45 15 675
44 29 1276
43 36 1548
42 45 1890
41 45 1845
40 59 2360
39 71 2769
38 51 1938
37 72 2664
36 77 2772
35 74 2590
34 72 2448
33 82 2706
32 90 2880
31 74 2294
30 69 2070
29 47 1363
28 30 840
27 27 729
26 26 676
25 21 525
24 13 312
23 4 92
22 5 110
21 4 84
20 2 40
18 2 36
Total 1186 NULL
However, I can't seem to get SQL Server to display the total number of visits where it says NULL on the total row.
Any ideas?
I think you can just do:
sum(num_pat_visits) as tot_pat_visit
SELECT CASE GROUPING(num_pat_visits) WHEN 1 THEN 'Total'
ELSE CAST(num_pat_visits AS varchar(5)) END AS num_pat_visits,
COUNT(*) AS num_patients,
--num_pat_visits * COUNT(*) AS tot_pat_visit
sum(num_pat_visits) as tot_pat_visit
FROM
(SELECT patient_id, COUNT(*) AS num_pat_visits FROM #test GROUP BY patient_id) a
GROUP BY num_pat_visits WITH ROLLUP
ORDER BY CAST(num_pat_visits AS int) DESC;