Left Outer Join With Date Range Only Not Working As Expected - sql

I originally posted this question here but sadly now I have to dump the mortgage number filter. Which it turns out is a pain.
I'm using the following LOJ query which uses a CTE to generate a range of dates:
Declare #inquiryStartDate DateTime;
Declare #inquiryEndDate DateTime;
SET #inquiryStartDate = '2013-07-01';
SET #inquiryEndDate = '2013-07-31';
With DateRange As (
SELECT ID, Date
FROM d_Dates
WHERE (Date BETWEEN #inquiryStartDate AND #inquiryEndDate)
)
Select DateRange.ID, DateRange.Date,f_MortgageSnapshots.MortgageNumber, f_MortgageSnapshots.Investor_ID
From DateRange
LEFT OUTER JOIN f_MortgageSnapshots On DateRange.ID = f_MortgageSnapshots.SnapshotDate_ID
And I'm getting something like this:
But I want this:
What am I doing wrong? Can't I do a left join between tables in the case?
Quick note, There are just 2 rows in the f_MortgageSnapshots table for mortgage 12345678.
For those who are wondering, here's the d_Dates table:

It looks like d_dates does not contain a row for every possible date within your inquiry date range.
try something like:-
create function [dbo].BuildDataRange
(
#StartDate date,
#EndDate date
)
returns #returntable table
(
ID int,
[Date] date
)
as
begin
while #StartDate<=#EndDate begin
insert into #returntable (ID, [Date]) values (
DATEPART(year,#StartDate)*10000 +
DATEPART(month,#StartDate)*100 +
DATEPART(day,#StartDate),
#StartDate)
set #StartDate=DATEADD(day,1,#StartDate)
end
return
end
go
and then you should be able to:-
Declare #inquiryStartDate DateTime;
Declare #inquiryEndDate DateTime;
SET #inquiryStartDate = '2013-07-01';
SET #inquiryEndDate = '2013-07-31';
select *
from [dbo].BuildDataRange(#inquiryStartDate, #inquiryEndDate) dr
left join f_MortgageSnapshots On dr.ID = f_MortgageSnapshots.SnapshotDate_ID

Related

Iterate through derived value from temp table so it value can be used it a where condition using for loop

I can get the total for each of the items from a derived table like so:
declare #laneNum int
declare #startDate date = '2019-02-07'
declare #class int = 1
declare #id int
if OBJECT_ID('tempdb..#tempLaneNumber') IS NOT NULL
drop table [#tempLaneNumber]
create table #tempLaneNumber
(
LANE_NUMBER INT NULL
)
INSERT INTO #tempLaneNumber (LANE_NUMBER)
SELECT DISTINCT EXIT_LANE
FROM [dbo].[TOLL]
ORDER BY EXIT_LANE DESC
select l.LANE_NUMBER, COUNT(*)
from [dbo].[TOLL] t
inner join #tempLaneNumber l on t.EXIT_LANE = l.LANE_NUMBER
where convert(date, TRXN_DTIME) = #startDate
GROUP BY l.LANE_NUMBER
But what I need now is to iterate through each of the derived values so I can use it in a statement where each result can be placed in a variable. This is what I get in my current code...
I need to put LANE_NUMBER 4 into x4 variable and LANE_NUMBER 6 into x6 variable and so forth. How do I get to it?
EDIT
declare #laneNum int
declare #startDate date = '2019-02-07'
declare #class int = 1
declare #id int
if OBJECT_ID('tempdb..#tempLaneNumber') IS NOT NULL
drop table [#tempLaneNumber]
create table #tempLaneNumber
(
LANE_NUMBER INT NULL
)
INSERT INTO #tempLaneNumber (LANE_NUMBER)
SELECT DISTINCT EXIT_LANE
FROM [dbo].[TOLL]
ORDER BY EXIT_LANE DESC
;WITH CTE AS
(
select l.LANE_NUMBER, COUNT(*) CT
from [dbo].[TOLL] t
inner join #tempLaneNumber l on t.EXIT_LANE = l.LANE_NUMBER
where convert(date, TRXN_DTIME) = #startDate
GROUP BY l.LANE_NUMBER
)
SELECT * FROM CTE where LANE_NUMBER = 4
This is about right but the problem is I would need to hardcode the value "4" or "6" or "7". This sample has 4 results so it's okay. but what if I have 10 or more?
If you want to use the result later on you can use temp table like following.
create table #Results
(
LANE_NUMBER INT NULL,
[Count_LN] INT
)
INSERT INTO #Results
select l.LANE_NUMBER, COUNT(*) CT
from [dbo].[TOLL] t
inner join #tempLaneNumber l on t.EXIT_LANE = l.LANE_NUMBER
where convert(date, TRXN_DTIME) = #startDate
GROUP BY l.LANE_NUMBER
If you want to use the output immediately in the next statement, you can go for CTE like following.
;WITH CTE AS
(
select l.LANE_NUMBER, COUNT(*) CT
from [dbo].[TOLL] t
inner join #tempLaneNumber l on t.EXIT_LANE = l.LANE_NUMBER
where convert(date, TRXN_DTIME) = #startDate
GROUP BY l.LANE_NUMBER
)
SELECT * FROM CTE --USER YOUR CTE HERE
EDIT:
I am not able to understand your requirement fully, by any reason if you want to iterate the table and store every row's column value into a variable, you can try like following.
create table #Results
(
LANE_NUMBER INT NULL,
[Count_LN] INT
)
INSERT INTO #Results
select l.LANE_NUMBER, COUNT(*) CT
from [dbo].[TOLL] t
inner join #tempLaneNumber l on t.EXIT_LANE = l.LANE_NUMBER
where convert(date, TRXN_DTIME) = #startDate
GROUP BY l.LANE_NUMBER
declare #ln int
declare #ct int
While (Select Count(*) From #Results) > 0
Begin
select top 1 #ln = LANE_NUMBER, #ct = [Count_LN] from #Results
-- Use the variable #ln and #ct. For example, if you want to call a sp
-- exec call_someothersp #ln,#ct
Delete From #Results Where LANE_NUMBER = #ln and [Count_LN]=#ct
End

SQL where clause not getting filtered

I have the following query, but it is not giving any regard to the in the p.created_by =#searchBy where clause, how to correct it so that the results would be filtered according #searchBy too.
ALTER PROC [dbo].[Rptcashcollectionouter] #branchId INT,
#searchBy INT,
#strDate DATETIME=NULL,
#endDate DATETIME=NULL
AS
BEGIN
SELECT DISTINCT p.created_on AS paid_date
FROM reading re
JOIN billing_gen bg ON re.id = bg.reading_id
JOIN customer_registration cr ON bg.account_number = cr.account_number
JOIN payment p ON bg.bill_number = p.bill_number
JOIN customer_category cc ON cr.customer_category_id = cc.id
WHERE p.created_by = #searchBy
AND ( ( #strDate IS NULL )
OR Cast(Floor(Cast(p.created_on AS FLOAT)) AS DATETIME) >=
Cast(Floor(Cast(#strDate AS FLOAT)) AS DATETIME) )
AND ( ( #endDate IS NULL )
OR Cast(Floor(Cast(p.created_on AS FLOAT)) AS DATETIME) <=
Cast(Floor(Cast(#endDate AS FLOAT)) AS DATETIME) )
AND cr.branch_id = #branchId
ORDER BY p.created_on ASC;
END;
Check the value inside your procedure as below.
SELECT #branchId, #searchBy, #strDate,#endDate
And, then try to run the SQL manually with the same value. Also, make sure you have data in your table for your criteria.
Also, what exactly you are trying here ?
Cast(Floor(Cast(p.created_on AS FLOAT)) AS DATETIME)
While executing procedure, make sure you are passing properly value.
Print out all values that are coming (Just for testing).
#searchBy INT is of integer type. But i think "p.created_by =#searchBy" is a type of datetime or date , so it may also conflicts here, or display wrong result. In below line. p.created_by is treating as a datetime or date and #searchby in integer.
WHERE p.created_by = #searchBy

T-SQL Dynamic variable insert

can some one help, with this query. I have 10 rows in my temp table
Declare #date date = '2014-11-01'
Declare #iDate int = '20141101'
Create table #test33(Paname varchar(100))
insert into #test33
Go
Now i have 10 rows in temp table. I want to insert those temp values in my cte dynamically
Declare #StartDate date = '2014-11-01'
Declare #EndDate date = '2014-11-30'
Declare #Paname nvarchar(100) = 'MPU' --- i have multiple panames how can i insert dyamically in cte or any other solution?
;with pla as
( SELECT*
FROM [dbo].[Pla] pl
JOIN dbo.testplan cl
ON pl.ClientId = cl.ClientId
where pl.name = #Paname
and pl.StartDate >= #StartDate and pl.EndDate <= #EndDate
)
select * from pla
You can loop throw multiple parameters using WHILE or using CURSOR. Inside it you can used dynamic sql:
declare #DSQL varchar(MAX)
SET #DSQL = ';with pla as
( SELECT*
FROM [dbo].[Pla] pl
JOIN dbo.testplan cl
ON pl.ClientId = cl.ClientId
where pl.name = '+#Paname+'
and pl.StartDate >= '+#StartDate+' and pl.EndDate <= '+#EndDate+'
)
select * from pla'
EXEC(#DSQL)

Check if date is exists among the dates then add extra one day to that date

i want to add the days(for example 3 days) to the given date. Before adding days we can check the holidays which are already configured in one table.
Here is my sample code. But i am unable to achieve it.
declare #HolidaysList NVARCHAR(250) = '2014-06-29,2014-07-02,2014-07-18,2014-07-30,2014-10-26'
DECLARE #RDATE DATE = '2014-06-28'
declare #addDays int = 3
declare #count int = 0
while(#count < #addDays)
BEGIN
set #RDATE = DATEADD(DAY,1,#RDATE)
--print '1 ' +cast( #RDATE as nvarchar(100))
if exists(SELECT ITEM FROM fnSplit(#HolidaysList,',') WHERE item = #RDATE)
begin
SELECT #RDATE= CONVERT(VARCHAR(10),DATEADD(DAY,1,#RDATE),101)
PRINT 'if '+ CAST( #HRDATE AS NVARCHAR(100))
end
set #count = #count+1
END
PRINT #RDATE
Here fnSplit is a function which returns a table.
In the above script i have to add 3 days to #RDate. Before adding i have to check holidays list i.e in #HolidaysList. If holiday is come then we can add extra date.
in the above script the output is: 2014-08-03 because 29th is holiday and 2nd is also holiday. so output will be 2014-08-03
You can do this without loops:
DECLARE #Holidays TABLE (Item DATE);
INSERT #Holidays
VALUES ('2014-06-29'),('2014-07-02'),('2014-07-18'),('2014-07-30'),('2014-10-26');
DECLARE #RDATE DATE = '2014-06-28',
#addDays INT = 3;
WITH CTE AS
( SELECT *,
RowNumber = ROW_NUMBER() OVER(ORDER BY d.Date)
FROM ( SELECT DATEADD(DAY, ROW_NUMBER() OVER(ORDER BY object_id), #RDATE)
FROM sys.all_objects
) AS d (Date)
WHERE NOT EXISTS
( SELECT 1
FROM #Holidays AS h
WHERE h.Item = d.Date
)
)
SELECT Date
FROM CTE
WHERE RowNumber = #addDays;
The principal is this part:
SELECT Date = DATEADD(DAY, ROW_NUMBER() OVER(ORDER BY object_id), #RDATE)
FROM sys.all_objects
Will just generate a list of dates onwards from your starting date. You then exclude all holidays from this list using NOT EXISTS, and add a rank to all these days using ROW_NUMBER(). It is then just a case of selecting the date with the required rank.
declare #HolidaysList NVARCHAR(250) = '2014-06-29,2014-06-30,2014-07-01,2014-07-30,2014-07-18,2014-10-26'
DECLARE #RDATE DATE = '2014-06-28'
declare #addDays int = 3
declare #count int = 0
DECLARE #EXISTS int = 0
while(#count < #addDays)
BEGIN
set #RDATE = DATEADD(DAY,1,#RDATE)
if exists(SELECT ITEM FROM fnSplit(#HolidaysList,',') WHERE item = #RDATE)
set #EXISTS = #EXISTS+1
set #count = #count+1
END
if(#EXISTS is not null)
set #RDATE = DATEADD(DAY,#EXISTS,#RDATE)
print #RDATE

SQL Syntax to count unique users completing a task

I have the following code which shows me what users has completed ticket and this lists each user and the date they close a ticket. i.e.
Paul
Matt
Matt
Bob
Matt
Paul
Matt
Matt
At the moment I manually count each user myself to see their totals for the day.
EDIT: Changed output as columns instead of rows:
What I have been trying to do is get SQL Server to do this for me i.e. the final result to look like:
Paul | 2
Matt | 5
Bob | 1
My code I am currently using is and I would be greatful if someone can help me change this so I can get it outputting something similar to above?
DECLARE #StartDate DateTime;
DECLARE #EndDate DateTime;
-- Date format: YYYY-MM-DD
SET #StartDate = '2013-11-06 00:00:00'
SET #EndDate = GETDATE() -- Today
SELECT (select Username from Membership where UserId = Ticket.CompletedBy) as TicketStatusChangedBy
FROM Ticket INNER JOIN
TicketStatus ON Ticket.TicketStatusID = TicketStatus.TicketStatusID INNER JOIN
Membership ON Ticket.CheckedInBy = Membership.UserId
WHERE TicketStatus.TicketStatusName = 'Completed' and Ticket.ClosedDate >= #StartDate --(GETDATE() - 1)
and Ticket.ClosedDate <= #EndDate --(GETDATE()-0)
ORDER BY Ticket.CompletedBy ASC, Ticket.ClosedDate ASC
Thank you for your help and time.
Not sure if you specifically want it in that format but if you had it in rows it's a lot simpler as a query:
SELECT Names, COUNT(Names)
FROM Table1
GROUP BY Names
SQL Fiddle
Declare #t table(names varchar(100))
DECLARE #StartDate DateTime;
DECLARE #EndDate DateTime;
-- Date format: YYYY-MM-DD
SET #StartDate = '2013-11-06 00:00:00'
SET #EndDate = GETDATE() -- Today
insert into #t(names)
SELECT (select Username from Membership where UserId = Ticket.CompletedBy) as TicketStatusChangedBy
FROM
Ticket INNER JOIN TicketStatus ON Ticket.TicketStatusID = TicketStatus.TicketStatusID INNER JOIN
Membership ON Ticket.CheckedInBy = Membership.UserId
WHERE TicketStatus.TicketStatusName = 'Completed' and Ticket.ClosedDate >= #StartDate
--(GETDATE() - 1)
and Ticket.ClosedDate <= #EndDate --(GETDATE()-0)
ORDER BY Ticket.CompletedBy ASC, Ticket.ClosedDate ASC
Select
sum(case when names='Paul' then 1 else 0 end) as Paul,
sum(case when names='Matt' then 1 else 0 end) as Matt,
.
.
.
from #t
CREATE TABLE SomeTable
(Name NVARCHAR(20))
GO
INSERT INTO SomeTable
VALUES ('Mark'), ('Mark'),('Mark'),('SAM'),('SAM'),('Josh')
GO
;WITH CTE
AS
(
SELECT NAME, COUNT(*) AS Total FROM SomeTable
GROUP BY Name
)
SELECT *
FROM CTE
PIVOT (
MAX(Total)
FOR NAME
IN ([Mark], [SAM], [Josh])
)l
Result Set
Mark SAM Josh
3 2 1
Obviously If there are many values in the table you will need to use Dynamic Sql, 1st build the Comma deliminited list of all the distinct values/names then pass the list of names in the 'IN' cluase of above query it to the Dynamic Sql.
Using Dynamic SQL
DECLARE #NameList NVARCHAR(MAX) = ''
DECLARE #Sql NVARCHAR(MAX)
SELECT #NameList = #NameList + ',[' + Name + ']'
FROM (SELECT DISTINCT NAME FROM SomeTable)t
SET #NameList = STUFF(#NameList, 1, 1, '')
PRINT #NameList --<---- for checking purpose to see if list is as expected
SET #Sql = ';WITH CTE
AS
(
SELECT NAME, COUNT(*) AS Total FROM SomeTable
GROUP BY Name
)
SELECT *
FROM CTE
PIVOT (
MAX(Total)
FOR NAME
IN ('+ #NameList + ')
)l'
EXECUTE sp_executesql #Sql
Result Set
Mark SAM Josh
3 2 1