Performance Issue in While Clause - sql-server

Okay everyone,
Apologies in advance for the length. This one's actually kind of fun, though.
I wrote up a SQL script that I was semi-proud of yesterday because I thought it was quite clever. Turns out it gets ruined by performance issues, and I can't even test it because of that, so it may not even be doing what I think sigh.
This problem is best explained with an example:
Column A | Column B | Column C | Column D
Heart | K | 2/1/2013 | 3/1/2013
Heart | K | 2/1/2013 | 3/1/2013
Heart | K | 1/1/2013 | 3/1/2013
Heart | K | 2/1/2013 | 4/1/2013
Spade | 4 | 2/1/2013 | 3/1/2013
Spade | 3 | 2/1/2013 | 3/1/2013
Club | 4 | 2/1/2013 | 3/1/2013
With this table I need to: 1. Starting with the first, update the row with the data following it if the values in Column A match, 2. delete the second row after the update if there was a match, and 3. move on to the next row if there was no match and rerun the same process.
If there's a match, the higher row updates based on the following:
Column A: Nothing
Column B: If both values are the same, keep the value in one, otherwise write 'Multiple'
Column C: Keep the earlier date between the two,
Column D: Keep the later date between the two,
Then I delete the lower row.
My example should result in the following:
Column A | Column B | Column C | Column D
Heart | K | 1/1/2013 | 4/1/2013
Spade | Multiple | 2/1/2013 | 3/1/2013
Club | 4 | 2/1/2013 | 3/1/2013
To do all this I created two table variables, inserted the same data into both, and then cycled through the second (#ScheduleB) looking for matches to update the row in the first table (#ScheduleA). I then deleted the row below the row in #A (because it's the same as B). Finally, when there wasn't a match, I moved to the next row in #A to start the process over. At least that's what the code's supposed to do -- see below.
The problem is performance is TERRIBLE. I've considered using a Cursor, but don't know if the performance would help there.
Any suggestions?
Declare #ScheduleA Table
(
RowNumber int,
Period nvarchar(MAX),
Program nvarchar(MAX),
ControlAccount Nchar(50),
WorkPackage Nchar(50),
CAM Nchar(50),
EVM Nchar(50),
Duration int,
BLStart datetime,
BLFinish datetime
)
Declare #ScheduleB Table
(
RowNumber int,
Period nvarchar(MAX),
Program nvarchar(MAX),
ControlAccount Nchar(50),
WorkPackage Nchar(50),
CAM Nchar(50),
EVM Nchar(50),
Duration int,
BLStart datetime,
BLFinish datetime
)
Insert INTO #ScheduleA
Select ROW_NUMBER() OVER(order by workpackage desc) as [Row], Period, Program,
ControlAccount, WorkPackage, CAM, EVM, Duration, BLStart, BLFinish
From ScheduleData
where program = #Program and period = #Period
Insert INTO #ScheduleB
Select ROW_NUMBER() OVER(order by workpackage desc) as [Row], Period, Program,
ControlAccount, WorkPackage, CAM, EVM, Duration, BLStart, BLFinish
From ScheduleData
where program = #Program and period = #Period
declare #i int = 1
declare #j int = 2
--Create a loop for the second variable that counts up to the last row of the B table
While #j < (select MAX(ROWNUMBER) + 1 from #ScheduleB)
Begin
--if the tables match by WorkPackage THEN
IF ((select WorkPackage from #ScheduleA where RowNumber = #i) =
(select workpackage from #ScheduleB where RowNumber = #j))
Begin
Update #ScheduleA
--Update the Schedule CAM, BLStart, BLFinish of the A table (if necessary)
set CAM =
Case
--Set values in #ScheduleA Column B based on logic
End,
BLStart =
Case
--Set values in #ScheduleA Column C based on logic
End,
BLFinish =
Case
--Set values in #ScheduleA Column D based on logic
End
Where RowNumber = #i
Delete from #ScheduleA
where RowNumber = #i + 1
set #j = #j + 1 --next row in B
End
ELSE
set #i = #i + 1
END
EDIT: To clarify, column B is NOT an integer column, I was simply using this as an example because cards are pretty easily understood. I've since updated the column to include K's.

Based on your requirements I think a solution like this would work:
SELECT
[column a],
CASE WHEN MAX([column b]) <> MIN([column b]) THEN 'multiple' ELSE CAST(MAX([column b]) AS NVARCHAR(10)) END,
MIN([column c]),
MAX([column d])
FROM Table
GROUP BY [column a]
EDIT:
SQL Fiddle

Related

How to display the "rows" which has value and NULL columns grouped separately

There is a table called 'member' which has 60 columns. Only some of the columns have values; 5 columns have values and the rest of 55 columns are NULL.
The problem is that the columns with values are scattered and I find it difficult to search the row to find the ones which have values.
I have tried a few suggestions which I received while posting this question. Below is one of them.
select * from table order by NULLIF(value,'') = '' DESC, value
I tried below
select * from member order by NULLIF(date_of_begin,'')
This doesn't satisfy my requirement when I want something like this. I use a select statement and segregate all columns having values to be displayed first and then all columns with NULL displayed last.
ID Member Name Age Gender Date of begin DOB DOC Extra
1 John 34 M 4/10/2019 NULL NULL NULL
2 Jack NULL M 4/11/2019 NULL NULL NULL
3 David 54 M 4/15/2019 NULL NULL NULL
4 Eric NULL M 4/16/2019 NULL NULL NULL
5 Ivan 45 M 4/10/2019 NULL NULL NULL
I want a select statement which will divide the above example with the below grouping. Age is NULL for Jack, so it should be placed in last column and displayed. This will make my work easier in finding which columns have NULL and which have values sorted.
For example-- >
Select * from member where id =2 IS NOT NULL (I need help here in this statement change)
Desired results:
ID Member Name Gender Date of begin DOB DOC Extra Age
2 Jack M 4/11/2019 NULL NULL NULL NULL
I'm not willing to swear this is worth the effort, but if you only need one ID at a time, or at least only a few, this will return only the non-null column values. If you wanted to go to even greater pain and try to pivot it back into rows, have at it, but this gets you a workable result set.
We're using CROSS APPLY to unpivot your results, and then dispose of the NULL values. You're data doesn't look like a row anymore, but the handful of data points you need are there for you.
Using the CROSS APPLY, in order to get all of the column values into one single column, I CAST them all as NVARCHAR data, so your results are all text fields.
In the example, I returned two ID values, just so you could see how that would look.
Data set up, in case anybody else wants to take a swing at this:
DECLARE #table TABLE(
ID INTEGER NOT NULL PRIMARY KEY
,Member_Name VARCHAR(5) NULL
,Age INTEGER NULL
,Gender VARCHAR(1) NULL
,Date_of_begin DATE NOT NULL
,DOB VARCHAR(4) NULL
,DOC VARCHAR(4) NULL
,Extra VARCHAR(4) NULL
);
INSERT INTO #table(ID,Member_Name,Age,Gender,Date_of_begin,DOB,DOC,Extra) VALUES (1,'John',34,'M','4/10/2019',NULL,NULL,NULL);
INSERT INTO #table(ID,Member_Name,Age,Gender,Date_of_begin,DOB,DOC,Extra) VALUES (2,'Jack',NULL,'M','4/11/2019',NULL,NULL,NULL);
INSERT INTO #table(ID,Member_Name,Age,Gender,Date_of_begin,DOB,DOC,Extra) VALUES (3,'David',54,'M','4/15/2019',NULL,NULL,NULL);
INSERT INTO #table(ID,Member_Name,Age,Gender,Date_of_begin,DOB,DOC,Extra) VALUES (4,'Eric',NULL,'M','4/16/2019',NULL,NULL,NULL);
INSERT INTO #table(ID,Member_Name,Age,Gender,Date_of_begin,DOB,DOC,Extra) VALUES (5,'Ivan',45,'M','4/10/2019',NULL,NULL,NULL);
Here's the query.
SELECT
c.*
FROM #table AS t
CROSS APPLY (VALUES ('ID',CAST(t.ID AS NVARCHAR(30))),
('Member_Name',CAST(t.Member_Name AS NVARCHAR(30))),
('Age',CAST(t.Age AS NVARCHAR(30))),
('Gender',CAST(t.Gender AS NVARCHAR(30))),
('Date_of_begin',CAST(t.Date_of_begin AS NVARCHAR(30))),
('DOB',CAST(t.DOB AS NVARCHAR(30))),
('DOC',CAST(t.DOC AS NVARCHAR(30))),
('Extra',CAST(t.Extra AS NVARCHAR(30)))
) c (ColName,ColValue)
WHERE t.ID IN (2,3)
AND c.ColValue IS NOT NULL
ORDER BY
t.ID,
CASE
WHEN c.ColName = 'ID' THEN 1
WHEN c.ColName = 'Member_Name' THEN 2
ELSE 3
END
Results:
+---------------+------------+
| ColName | ColValue |
+---------------+------------+
| ID | 2 |
| Member_Name | Jack |
| Gender | M |
| Date_of_begin | 2019-04-11 |
| ID | 3 |
| Member_Name | David |
| Age | 54 |
| Gender | M |
| Date_of_begin | 2019-04-15 |
+---------------+------------+
The solution I suggest is to store one record in n rows,
n is the number of columns,
then you can order the result as you wish using order by
or add the criteria based on NULL values
I am using the system sql server tables syscolumns and sysobjects
create table tab_mytable (id int ,colonne varchar(100),valeur varchar(100));
insert into tab_mytable(id,colonne) select c.colid,c.name from sysobjects o inner join
syscolumns c on o.id=c.id where o.name='member' order by c.colid
declare #cmd as varchar(1000)
declare #mytab as table (val varchar(100))
declare mycursor cursor for select colonne from tab_mytable
declare #colonne as varchar(100)
declare #val as varchar(100)
open mycursor
fetch mycursor into #colonne
while ##fetch_status=0
begin
set #cmd= 'select '+#colonne +' from member where id=2'
insert into #mytab exec(#cmd)
select #val=val from #mytab
set #cmd='update tab_mytable set valeur='''+#val+''' where colonne='''+#colonne+''''
exec(#cmd)
print #cmd
delete from #mytab
fetch mycursor into #colonne
end
close mycursor
deallocate mycursor
--Put here your Query to display teh results as you wish
select * from tab_mytable order by valeur
You can use also the UNPIVOT statement
But in that use you have to write all the column names, for the solution above, you won't write them in your script

Between two different range numbers

I have a stored procedure that has a table for a parameter with two columns: From and To. Both int. It is used for searching scores.
The example of the table is
+-----------+-------+----+
| RowNumber | From | To |
+-----------+-------+----+
| 1 | 0 | 30 |
| 2 | 60 | 80 |
+-----------+-------+----+
How can I search a table to have results that include all scores between 0 and 30 and 60 and 80?
I had tried between inside a while loop but nothing.
This is a guess in the absence of a reply, however, maybe...
CREATE TABLE Score (ID int IDENTITY(1,1),
Score int);
INSERT INTO Score
VALUES (65),(17),(97),(14),(34),(79),(37),(87),(65),(63),(15),(75),(05),(25),(38),(28),(88);
GO
CREATE TABLE ScoreRange (ID int IDENTITY(1,1),
[From] int, --Try to avoid keywords, and especially reserved words, for column names
[To] int); --Try to avoid keywords, and especially reserved words, for column names
INSERT INTO ScoreRange
VALUES (0,30),
(60,80);
GO
SELECT *
FROM Score S;
SELECT S.*
FROM Score S
JOIN ScoreRange SR ON S.Score BETWEEN SR.[From] AND SR.[To];
GO
DROP TABLE Score;
DROP TABLE ScoreRange;
It's kinda hard to answer without sample data - but I think you are looking for something like this:
SELECT t.*
FROM YourTable As t
JOIN #TVP As p ON t.Score >= p.[From] AND t.Score <= p.[To]
select * from t
where exists (
select 1 from ranges r
where t.val between r.from and r.to
);

Reverse order of a XML Column in SQL Server

In a SQL Server table, I have a XML column where status are happened (first is oldest, last current status).
I have to write a stored procedure that returns the statuses: newest first, oldest last.
This is what I wrote:
ALTER PROCEDURE [dbo].[GetDeliveryStatus]
#invoiceID nvarchar(255)
AS
BEGIN
SET NOCOUNT ON;
DECLARE #xml xml
SET #xml = (SELECT statusXML
FROM Purchase
WHERE invoiceID = #invoiceID )
SELECT
t.n.value('text()[1]', 'nvarchar(50)') as DeliveryStatus
FROM
#xml.nodes('/statuses/status') as t(n)
ORDER BY
DeliveryStatus DESC
END
Example of value in the statusXML column:
<statuses>
<status>A</status>
<status>B</status>
<status>A</status>
<status>B</status>
<status>C</status>
</statuses>
I want the procedure to return:
C
B
A
B
A
with ORDER BY .... DESC it return ALPHABETIC reversed (C B B A A)
How should I correct my procedure ?
Create a sequence for the nodes based on the existing order then reverse it.
WITH [x] AS (
SELECT
t.n.value('text()[1]', 'nvarchar(50)') as DeliveryStatus
,ROW_NUMBER() OVER (ORDER BY t.n.value('..', 'NVARCHAR(100)')) AS [Order]
FROM
#xml.nodes('/statuses/status') as t(n)
)
SELECT
DeliveryStatus
FROM [x]
ORDER BY [x].[Order] DESC
... results ...
DeliveryStatus
C
B
A
B
A
There is no need to declare a variable first. You can (and you should!) read the needed values from your table column directly. Best was an inline table valued function (rather than a SP just to read something...)
Better performance
inlineable
You can query many InvoiceIDs at once
set-based
Try this (I drop the mock-table at the end - carefull with real data!):
CREATE TABLE Purchase(ID INT IDENTITY,statusXML XML, InvocieID INT, OtherValues VARCHAR(100));
INSERT INTO Purchase VALUES('<statuses>
<status>A</status>
<status>B</status>
<status>A</status>
<status>B</status>
<status>C</status>
</statuses>',100,'Other values of your row');
GO
WITH NumberedStatus AS
(
SELECT ID
,InvocieID
, ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) AS Nr
,stat.value('.','nvarchar(max)') AS [Status]
,OtherValues
FROM Purchase
CROSS APPLY statusXML.nodes('/statuses/status') AS A(stat)
WHERE InvocieID=100
)
SELECT *
FROM NumberedStatus
ORDER BY Nr DESC
GO
--Clean-Up
--DROP TABLE Purchase;
The result
+---+-----+---+---+--------------------------+
| 1 | 100 | 5 | C | Other values of your row |
+---+-----+---+---+--------------------------+
| 1 | 100 | 4 | B | Other values of your row |
+---+-----+---+---+--------------------------+
| 1 | 100 | 3 | A | Other values of your row |
+---+-----+---+---+--------------------------+
| 1 | 100 | 2 | B | Other values of your row |
+---+-----+---+---+--------------------------+
| 1 | 100 | 1 | A | Other values of your row |
+---+-----+---+---+--------------------------+

How to retrieve unique records having unique values in two columns from a table in SQL Server

I want to query a table where I need the result that contains unique values from two columns together. For e.g.
Table
EnquiryId | EquipmentId | Price
-----------+--------------+-------
1 | E20 | 10
1 | E50 | 40
1 | E60 | 20
2 | E30 | 90
2 | E20 | 10
2 | E90 | 10
3 | E90 | 10
3 | E60 | 10
For each EnquiryId, EquipmentId will be unique in the table. Now I want a result where I can get something like this
EnquiryId | EquipmentId | Price
-----------+--------------+-------
1 | E20 | 10
2 | E30 | 90
3 | E90 | 10
In the result each enquiryId present in the table should be displayed uniquely.
If suppose I have 3 EquipmentIds "E20,E50,E60" for EnquiryId "1".. Any random EquipmentId should be displayed from these three values only.
Any help would be appreciated. Thank you in advance.
QUERY
;WITH cte AS
(
SELECT *,
ROW_NUMBER() OVER
(PARTITION BY enquiryID
ORDER BY enquiryID ) AS RN
FROM tbl
)
SELECT enquiryID,equipmentID,Price
FROM cte
WHERE RN=1
FIND FIDDLE HERE
The following code must help you..
Sorry that I ended up in a lengthy solution only. Run it in your SSMS and see the result.
Declare #tab table (EnquiryId int, EquipmentId varchar(10),Price int)
Insert into #tab values
(1,'E20',10),
(1,'E50',40),
(1,'E60',20),
(2,'E30',90),
(2,'E20',10),
(2,'E90',10),
(3,'E90',10),
(3,'E60',10)
----------------------------------------------
Declare #s int = 1
Declare #e int,#z varchar(10)
Declare #Equipment table (EquipmentId varchar(10),ind int)
Insert into #Equipment (EquipmentId) Select Distinct EquipmentId From #tab
Declare #Enquiry table (id int identity(1,1),EnquiryId int,EquipmentId varchar(10))
Insert into #Enquiry (EnquiryId) Select Distinct EnquiryId From #tab
Set #e = ##ROWCOUNT
While #s <= #e
begin
Select Top 1 #z = T.EquipmentId
From #tab T
Join #Enquiry E On T.EnquiryId = E.EnquiryId
Join #Equipment Eq On Eq.EquipmentId = T.EquipmentId
Where E.id = #s
And Eq.ind is Null
Order by NEWID()
update #Enquiry
Set EquipmentId = #z
Where id = #s
update #Equipment
Set ind = 1
Where EquipmentId = #z
Set #s = #s + 1
End
Select T.EnquiryId,T.EquipmentId,T.Price
From #tab T
left join #Enquiry E on T.EnquiryId = E.EnquiryId
Where T.EquipmentId = E.EquipmentId
You can use GROUP BY (Typical way) to remove duplicate value.
Basic steps are:
Alter table & Add Identity Column.
Group by columns which can be dupicate.
Delete those record.
Check here Remove Duplicate Rows from a Table in SQL Server

Counting records by year and month including zero counts

I am using an SQL Server Compact Edition server and I want to count the number of comments per month that correspond to a certain tutorial within a range of dates and include months which have a count of zero. I know I need to join a "calendar" table to my table to account for the missing months, but I need help with correct implementation of this.
I have a table of all the comments from different tutorials. This table is called Comments and the columns I need are [Tutorial] (nvarchar) and [DateAdded] (DateTime).
Tutorial | DateAdded
---------+-------------
sample | 2013-09-02
sample | 2013-09-04
sample | 2013-09-12
sample | 2013-09-12
example | 2013-09-15
sample | 2013-09-16
sample | 2013-09-21
sample | 2013-09-30
sample | 2013-10-01
sample | 2013-11-11
sample | 2013-11-11
example | 2013-11-14
sample | 2013-11-15
sample | 2013-11-19
sample | 2013-11-21
sample | 2013-11-25
sample | 2014-02-04
sample | 2014-02-06
And I have a Calendar table which has a year and month column like so:
Year | Month
-----+------
2000 | 01
2000 | 02
. | .
. | .
. | .
2099 | 12
If I were looking for the monthly count of the 'sample' comments from the past year (as of Feb. 14th, 2014), then the ideal output would be:
Tutorial | Year | Month | Count
---------+------+-------+------
sample | 2013 | 09 | 7
sample | 2013 | 10 | 1
sample | 2013 | 11 | 6
sample | 2013 | 12 | 0
sample | 2014 | 01 | 0
sample | 2014 | 02 | 2
I was able to figure out how to do the following query, but I need the months that do not have comments to return 0 as well.
SELECT
Tutorial,
datepart(year, DateAdded) AS Year,
datepart(month, DateAdded) AS Month,
COUNT(*) AS Count From Comments
WHERE
DateAdded > DATEADD(year,-1,GETDATE())
AND
Tutorial='sample'
GROUP BY
Tutorial,
datepart(year, DateAdded),
datepart(month, DateAdded)
Output using sample data from above.
Tutorial | Year | Month | Count
---------+------+-------+------
sample | 2013 | 09 | 7
sample | 2013 | 10 | 1
sample | 2013 | 11 | 6
sample | 2014 | 02 | 2
I know I need to join the tables, but I can't seem to figure out which join to use or how to implement it correctly. Please keep in mind that this is for SQL Server CE, so not all commands from SQL Server can be used.
Thanks so much in advance!
If you have a Calendar table with Month and Year you should try something like
SELECT t2.Tutorial, t1.[Month], t1.[Year], COALESCE(t2.Number, 0) AS Result
FROM Calendar AS t1 LEFT JOIN (
SELECT
Tutorial,
CONVERT(NCHAR(6), DateAdded, 112) AS tutDate,
COUNT(*) AS Count From Comments
WHERE
DateAdded > DATEADD(year,-1,GETDATE())
AND
Tutorial='sample'
GROUP BY
Tutorial,
CONVERT(NCHAR(6), [Order Date], 112)
) AS t2
ON (t1.[Year] + t1.[Month]) = t2.tutDate
ORDER BY t1.[Year] + t1.[Month]
What follows is a standalone script you can use to try things out and not touch any of your real database objects in production. The bottom third of the code contains the help with the joins you're looking for.
SQL Server CE will allow you to write a stored procedure, which can in turn be used as the source of a report. Stored procs are nice because they can take input parameters, something that is ideal for doing reporting.
-- create dummy Comments table for prototyping
create table #Comments (
ID int identity(1,1) not null,
Tutorial nvarchar(50) not null,
DateAdded datetime not null,
primary key clustered(DateAdded,ID,Tutorial)
);
-- populate dummy Comments table
declare #startDate datetime = '2000-01-01';
declare #endDate datetime = '2014-02-14';
declare #numTxns int = 5000;
set nocount on;
declare #numDays int = cast(#endDate as int) - cast(#startDate as int) + 1;
declare #i int = 1;
declare #j int = #i + #numTxns;
declare #rnd float;
while #i <= #j
begin
set #rnd = RAND();
insert into #Comments (Tutorial,DateAdded)
select
-- random tutorial titles
coalesce (
case when #rnd < .25 then 'foo' else null end,
case when #rnd between .5 and .75 then 'baz' else null end,
case when #rnd > .75 then 'qux' else null end,
'bar'
) as Tutorial,
-- random dates between #startDate and #endDate
cast(cast(rand() * #numDays + #startDate as int) as datetime) as DateAdded
set #i = #i + 1
end;
-- try deleting some months to see what happens
delete from #Comments
where DateAdded between '2013-11-01' and '2013-11-30'
or DateAdded between '2014-01-01' and '2014-01-31';
set nocount off;
go
-- ### following could easily be rewritten as a stored procedure
-- stored procedure parameters
declare #startDate datetime = '2000-01-01';
declare #endDate datetime = '2014-03-31';
-- pick only one option below
--declare #Tutorial nvarchar(50) = 'foo'; -- this only gets data for Tutorials called 'foo'
declare #Tutorial nvarchar(50) = 'all'; -- this gets data for all tutorials
-- begin stored procedure code
set nocount on;
-- this temp table is an alternative to
-- creating ***and maintaining*** a table full of dates,
-- months, etc., and cluttering up your database
-- in production, it will automatically delete itself
-- once the user has completed running the report.
create table #dates (
DateAdded datetime not null,
YearAdded int null,
MonthAdded int null,
primary key clustered (DateAdded)
);
-- now we put dates into #dates table
-- based on the parameters supplied by
-- the user running the report
declare #date datetime = #startDate;
while #date <= #endDate
begin
insert into #dates
select #date, YEAR(#date), MONTH(#date);
set #date = #date + 1;
end;
-- ## Why put every day of the month in this table?
-- ## I asked for a monthy report, not daily!
-- Yes, but looping through dates is easier, simply add 1 for the next date.
-- You can always build a monthly summary table later if you'd like.
-- This *is* kind of a brute-force solution, but easy to write.
-- More answers to this question in the code below, where they'll make more sense.
set nocount off;
-- now we return the data to the user
-- any month with no Tutorials will still show up in the report
-- but the counts will show as zero
select YearAdded, MonthAdded, SUM(Count_From_Comments) as Count_From_Comments,
SUM(foo) as Count_Foo, SUM(bar) as Count_Bar,
SUM(baz) as Count_Baz, SUM(qux) as Count_Qux
from (
-- ## you can reuse the following code for a detail report by day
-- ## another answer to 'Why not by month?' from above
-- start daily report code
select t1.DateAdded, t1.YearAdded, t1.MonthAdded, t2.Tutorial,
coalesce(Count_From_Comments,0) as Count_From_Comments,
case when t2.Tutorial = 'foo' then 1 else 0 end as foo,
case when t2.Tutorial = 'bar' then 1 else 0 end as bar,
case when t2.Tutorial = 'baz' then 1 else 0 end as baz,
case when t2.Tutorial = 'qux' then 1 else 0 end as qux
from #dates as t1 -- no where clause needed because #dates only contains the ones we want
left join ( -- left join here so that we get all dates, not just ones in #Comments
select *, 1 AS Count_From_Comments
from #Comments
where #Tutorial in (Tutorial,'all')
) as t2
on t1.DateAdded = t2.DateAdded -- ## join on one field instead of two, another answer to 'Why not by month?' from above
-- end daily report code
) as qDetail
group by YearAdded, MonthAdded
order by YearAdded, MonthAdded
-- end stored procedure code
go
-- ## Not required in production code,
-- ## but handy when testing this script.
drop table #dates;
-- #### Since this will be a real table in production
-- #### we definitely only want this for testing!
drop table #Comments;
go
Happy coding.

Resources