Loop Through 1 SQL Query, Instead Of Using 2 Queries - sql

Below I have a variable with two basic SELECT statements. If the user can only use one variable, #StartDate, to enter a date parameter, how can a query be looped through to only use one SELECT statement instead of two like you see below. So, imagine you don't have both queries, but one query and it can only be ran once but satisfy the 2 conditions in the WHERE clauses below, which are "FullDate = #StartDate" and "Fulldate BETWEEN DATEADD(mm, DATEDIFF(mm, 0, #StartDate), 0) AND #StartDate". SO, essentially I am trying to squeeze two SELECT statements into one and provide the relevant data from both queries. UNION ALL cannot be used here.
DECLARE #StartDate DATE = '20170610'
SELECT
FirstName,
LastName,
SUM(MoneySpent) AS 'Spent'
FROM
TableOne
WHERE
FullDate = #StartDate;
GROUP BY FirstName, LastName
SELECT
FirstName,
LastName,
SUM(MoneySpent) AS 'Spent'
FROM
TableOne
WHERE
Fulldate BETWEEN DATEADD(mm, DATEDIFF(mm, 0, #StartDate), 0) AND #StartDate;
GROUP BY FirstName, LastName

If you have two dates #Date1 and #Date2, then you can use this:
SELECT
FirstName,
LastName,
SUM(CASE WHEN FullDate = #Date1 THEN MoneySpent ELSE 0 END) AS 'SpentDate1',
SUM(CASE WHEN FullDate = #Date2 THEN MoneySpent ELSE 0 END) AS 'SpentDate2'
FROM
TableOne
WHERE
FullDate = #Date1 OR FullDate = #Date2
GROUP BY FirstName, LastName
BTW, UNION ALL can be used as well, you just need wrap it as subquery and use additional GROUP BY

Something you need to know about BETWEEN is that it includes the endpoints, so you only need the second query to obtain what you are looking for.
SELECT
FirstName,
LastName,
SUM(MoneySpent) AS 'Spent'
FROM
TableOne
WHERE
Fulldate BETWEEN DATEADD(mm, DATEDIFF(mm, 0, #StartDate), 0) AND #StartDate;
GROUP BY FirstName, LastName

I think the first query is already covered by the second query.
SELECT FirstName ,
LastName ,
SUM(MoneySpent) AS 'Spent'
FROM TableOne
WHERE Fulldate BETWEEN DATEADD(mm, DATEDIFF(mm, 0, #StartDate), 0)
AND #StartDate
GROUP BY FirstName, LastName
But for the sake of argument, one of many options is that you can put the relevant data of each query into a temporary table.
E.g.
DECLARE #StartDate DATE = '2017.06.10';
IF ( OBJECT_ID('tempdb..#tempTbl') IS NOT NULL )
BEGIN
DROP TABLE #tempTbl
END
CREATE TABLE #tempTbl
(
ID INT IDENTITY(1, 1)
PRIMARY KEY ,
FirstName VARCHAR(100) ,
LastName VARCHAR(100) ,
Spent MONEY
)
INSERT INTO #tempTbl
( FirstName ,
LastName ,
Spent
)
SELECT FirstName ,
LastName ,
SUM(MoneySpent) AS 'Spent'
FROM TableOne
WHERE FullDate = #StartDate
INSERT INTO #tempTbl
( FirstName ,
LastName ,
Spent
)
SELECT FirstName ,
LastName ,
SUM(MoneySpent) AS 'Spent'
FROM TableOne
WHERE Fulldate BETWEEN DATEADD(mm, DATEDIFF(mm, 0, #StartDate), 0)
AND #StartDate
SELECT FirstName,LastName,Spent
FROM #tempTbl
GROUP BY FirstName, LastName

I think,Here you nitice that One Resultset is subset of another resultset.
In other word,Range Between condition satify equal condition.So result is not repeated.
Example using AdventureWorks2012
DECLARE #StartDate DATE = '20020224'
DECLARE #StartDate1 DATE = '20020303'
select a.BusinessEntityID
,a.RateChangeDate,sum(a.rate) Rate
from HumanResources.EmployeePayHistory a
where a.RateChangeDate
BETWEEN DATEADD(mm, DATEDIFF(mm, 0, #StartDate), 0) AND #StartDate
or a.RateChangeDate=#StartDate1
GROUP by a.BusinessEntityID,a.RateChangeDate
here Result of both date is visisble (6 rows)
if we make it this
DECLARE #StartDate DATE = '20020224'
DECLARE #StartDate1 DATE = StartDate
here since between condtion satify RateChangeDate=#StartDate1
so output is only 5 rows
so what you are thinking is cannot be achieve.
If I had same problem then I will use only select ... FullDate between
And in front end I will pull data for fulldate=#StartDate
If you really use 2 Select like now you doing then do this,
;With CTE as
(
SELECT
FirstName,
LastName,
Fulldate,
SUM(MoneySpent) AS 'Spent'
FROM
TableOne
WHERE
Fulldate BETWEEN DATEADD(mm, DATEDIFF(mm, 0, #StartDate), 0) AND #StartDate;
GROUP BY FirstName, LastName,Fulldate
)
select *,0 flg from cte
union ALL
select * ,1 flg from cte
where Fulldate=#StartDate

Related

SQL Same Colum for differnet date

Look for some assistance. I want to query in one result comparison from one column comparing year results.
I can get it fine with 2 selects as follows, but not one. ANy thoughts?
DECLARE #CYBeginDate datetime
, #CYEndDate datetime
, #LYBeginDate datetime
, #LYEndDate datetime
, #2YBeginDate datetime
, #2YEndDate datetime
select #CYBeginDate = dateadd(year, datepart(year, getdate()) - 1900, '1900-07-01')
select #CYEndDate = dateadd(day, -1, dateadd(month, 12, #CYBeginDate))
select #LYBeginDate = dateadd(year, -1, #CYBeginDate)
select #LYEndDate = dateadd(year, -1, #CYEndDate)
select #2YBeginDate = dateadd(year, -2, #CYBeginDate)
select #2YEndDate = dateadd(year, -2, #CYEndDate)
Select ClientName, ClassOfRiskname, SUM([GrossEarningsNetGST]) AS 'This Year Earnings', NUll
from Reports_Policy_Transactions
where EffectiveDate between #CYBeginDate and #CYEndDate
AND ClientId = 77942
Group By ClientName, ClassOfRiskname
Select Null, Null, Null, SUM([GrossEarningsNetGST]) AS 'Last Year Earnings'
from Reports_Policy_Transactions
where EffectiveDate between #LYBeginDate and #LYEndDate
AND ClientId = 77942
Group By ClientName, ClassOfRiskname
not sure what does second select mean by all null values , but here is how you can merge two queries, but it really depends on your data , It might not work for your data and you might still need to keep where clause with dates and combine them using or
Select ClientName
, ClassOfRiskname
, SUM(case when EffectiveDate between #LYBeginDate and #LYEndDate then [GrossEarningsNetGST] else 0 end ) AS 'This Year Earnings'
, SUM(case when EffectiveDate between #CYBeginDate and #CYEndDate then [GrossEarningsNetGST] else 0 end ) AS 'Last Year Earnings'
from Reports_Policy_Transactions
where ClientId = 77942
Group By ClientName, ClassOfRiskname

SQL Server : CASE-WHEN returns error in select list or Not-exist block if used in both

In the below SQL Server 2008 select statement Case-When is used in 2 places, in the select list and inside NOT EXISTS: CASE-1 and CASE-2.
It works only if I comment out one of case-when statements, only if I use it only in one place: select list OR not-exist.
If it used in both places, as below, I get error:
Conversion failed when converting date and/or time from character string.
I did my research, read http://www.fmsinc.com/free/newtips/sql/sqltip10.asp, but I still can not make it work.
Please help, what is wrong with code below? Thank you
MyTable.dob is nvarchar(10)
PayrollTable.date_of_birth is varchar(10)
Both dob columns are nullable.
MyTable.dob is in format mmddyy like '010255'.
PayrollTable.date_of_birth is in format 'mm/dd/yyyy' like '01/02/1955'
Code:
SELECT
FName,
LName,
( --- CASE-1
select
CASE
WHEN CONVERT(DATE, STUFF(STUFF(a.dob,3,0,'/'),6,0,'/')) > GETDATE()
THEN CONVERT(varchar(10), DATEADD(yy, -100, CAST(STUFF(STUFF(a.dob,3,0,'/'),6,0,'/') AS DATE)), 101)
ELSE CONVERT(varchar(10), CAST(STUFF(STUFF(a.dob,3,0,'/'),6,0,'/') AS DATE), 101)
END) as dob1
FROM
MyTable a
INNER JOIN
(SELECT
FName, LName, dob,
-- StartDate source format = yyyymm - 200104 , --- result = 2001-04-01 as DATE
MAX(CAST((STUFF(StartDate,5,0,'-') + '-01') AS DATE) ) as StartDate -- original format yyyymm
FROM
MyTable
WHERE
-- mmddyy
CAST(SUBSTRING( dob, 5, 2) as INT) > 31 --yy
AND dob != '999999'
GROUP BY
FName, LName, dob --'mmddyy'
) as t ON
LTRIM(RTRIM(a.FName)) = LTRIM(RTRIM(t.FName)) AND LTRIM(RTRIM(a.LName)) = LTRIM(RTRIM(t.LName))
AND
a.dob = t.dob --'mmddyy'
AND
CAST((STUFF(a.StartDate,5,0,'-') + '-01') AS DATE) = t.StartDate
WHERE ((LTRIM(RTRIM(a.FName)) != '' and
a.FName is not null) or
( LTRIM(RTRIM(a.LName)) != '' and a.LName is not null ) )
and
NOT EXISTS ----------------------------------
-- player does NOT exist in Party DIM alerady
(
select *
from PayrollTable p --- PARTY
where
p.date_of_birth = --t.dob -- varchar(10) 1980-09-07 p.date_of_birth
( -- CASE-2
select
CASE
WHEN CONVERT(DATE, STUFF(STUFF(t.dob,3,0,'/'),6,0,'/')) > CAST(GETDATE() as DATE) --t.dob
THEN CONVERT(varchar(10), DATEADD(yy, -100, CAST(STUFF(STUFF(t.dob,3,0,'/'),6,0,'/') AS DATE)), 101)
ELSE CONVERT(varchar(10), CAST(STUFF(STUFF(t.dob,3,0,'/'),6,0,'/') AS DATE), 101) --t.dob
END
)
and
p.first_name = t.FName
and
p.last_name = t.LName
)
your problem is here.
select *
from PayrollTable p --- PARTY
where
p.date_of_birth = --t.dob -- varchar(10) 1980-09-07 p.date_of_birth
( -- CASE-2
select
CASE
WHEN CONVERT(DATE, STUFF(STUFF(t.dob,3,0,'/'),6,0,'/')) > CAST(GETDATE() as DATE) --t.dob
THEN CONVERT(varchar(10), DATEADD(yy, -100, CAST(STUFF(STUFF(t.dob,3,0,'/'),6,0,'/') AS DATE)), 101)
-- MISSING A WHEN CONDITION HERE
THEN DATEADD(yy, -100, CAST(STUFF(STUFF('090780',3,0,'/'),6,0,'/') AS DATE))
ELSE CONVERT(varchar(10), CAST(STUFF(STUFF(t.dob,3,0,'/'),6,0,'/') AS DATE), 101) --t.dob
END
)

RUN Query based on a given condition

Hi Guys i want to run this query based on condition following condition. if parameter date is less than 01/01/16 it should run the first CTE else the 2nd CTE thanks
DECLARE #Date AS DATET
SET #Date = '2015-10-31'
;WITH OLDVTE AS (SELECT
SalesID,
City,
Amount,
SalesDate
FROM INFO.SALESOLD
),
NEWVTE AS (
SalesID,
City,
Amount,
SalesDate
FROM INFO.SALESNEW
)
SELECT
CASE WHEN GETDATE() <= #Date THEN
(SELECT * FROM OLDVTE)
ELSE
(SELECT * FROM NEWVTE)
END AS DD
You might try something like this:
DECLARE #Date AS DATE = {d'2015-10-31'}
DECLARE #CurrentDateTime DATETIME = GETDATE();
SELECT
SalesID,
City,
Amount,
SalesDate
FROM INFO.SALESOLD
WHERE #CurrentDateTime <= #Date
UNION ALL
SELECT
SalesID,
City,
Amount,
SalesDate
FROM INFO.SALESNEW
WHERE #CurrentDateTime > #Date
The UNION ALL will return both results in one. But there will be only one of the selects returning rows actually...
Hint
I actually doubt, that your filter against GETDATE() would work as you expect it...
You could try with IF ELSE like below..
DECLARE #Date AS DATETIME
SET #Date = '2015-10-31'
If GETDATE() <= #Date--will this clause work..
select * FROM INFO.SALESOLD
Else
select * FROM INFO.SALEnew
You could also join the two tables if they contain any common field and pass date

SQL Server : datetime incorrect results

Using SQL Server 2008,
I have a procedure as follows:
SELECT
UserId, Name, Company, LanguageId, CodeRegisteredWith, TotalLoggedInDuration,
Region, IsAdmin,
IsRep, IsRetailer, IsTeamLeader, [dateregistered]
FROM
RoundupAcademy.dbo.UserProfile WITH(NOLOCK)
WHERE
(Convert(smalldatetime, DateRegistered, 120) >= Convert(smalldatetime, '2013-1-1', 120)
AND (Convert(smalldatetime, DateRegistered, 120) <= convert(smalldatetime, '2013-8-8', 120)))
This works fine and shows the results between the dates.
However when expanding on this query and some more conditions as follows:
SELECT
UserId, Name, Company, LanguageId, CodeRegisteredWith, TotalLoggedInDuration,
Region, IsAdmin, IsRep, IsRetailer, IsTeamLeader, [dateregistered]
FROM
RoundupAcademy.dbo.UserProfile WITH(NOLOCK)
WHERE
UserId is not null OR UserId not like ''
AND
(#LanguageID = 0 OR ([LanguageID] = #LanguageID ))
AND
((Convert(smalldatetime, DateRegistered, 120) >= Convert(smalldatetime, #datereg, 120)
AND (Convert(smalldatetime, DateRegistered, 120) <= convert(smalldatetime, #dateend, 120))))
it seems any date shows.
not sure what the problem is as my other conditions look fine.
any ideas?
Replace
WHERE UserId is not null OR UserId not like ''
with
WHERE (UserId is not null OR UserId not like '')
Otherwise you would get all records where UserId is not null or the other conditions are true.
query should be like these
SELECT UserId, Name, Company, LanguageId, CodeRegisteredWith, TotalLoggedInDuration, Region, IsAdmin,
IsRep, IsRetailer, IsTeamLeader, [dateregistered] FROM RoundupAcademy.dbo.UserProfile WITH(NOLOCK)
WHERE( UserId is not null OR UserId not like '')
AND
(#LanguageID = 0 OR ([LanguageID] = #LanguageID ))
AND
((Convert(smalldatetime,DateRegistered, 120) >= Convert(smalldatetime,#datereg, 120)
AND (Convert(smalldatetime,DateRegistered, 120) <= convert(smalldatetime,#dateend, 120))))

Function with recursive CTE seems to be very slow

I am currently working on a function in which I use a recursive CTE, but it seems that have poor performance. I need this to be in function (so no temp tables) so I can easily use it within stored procedures.
Here is the code:
CREATE FUNCTION [dbo].[Web_GetDailyLoadListUDF]
(
#CustomerID INT
, #StartDate DATETIME
, #Days INT
, #IncludeChildren BIT
)
RETURNS #TableOfValues TABLE
(
RowID SMALLINT IDENTITY(1,1)
, DailyLoadCount INT
, DailyLoadDate VARCHAR(6)
, FullDate DATETIME
)
AS
BEGIN
DECLARE #MaxDate DATETIME;
SET #MaxDate = DATEADD(dd, #Days * -1.7, DATEDIFF(dd, 0, #StartDate));
WITH DateCTE AS
(
SELECT DATEADD(dd, 0, DATEDIFF(dd, 0, #StartDate)) AS DateValue
UNION ALL
SELECT DATEADD(DAY, -1, DateValue)
FROM DateCTE
WHERE DATEADD(DAY, -1, DateValue) > #MaxDate
)
INSERT INTO #TableOfValues
SELECT * FROM
(
SELECT TOP (#Days)
(
SELECT COUNT(*)
FROM dbo.[Load] l WITH (NOLOCK)
JOIN dbo.LoadCustomer lc WITH (NOLOCK)
ON lc.LoadID = l.ID
JOIN dbo.Customer c WITH (NOLOCK)
ON c.ID = lc.CustomerID
WHERE DATEADD(dd, 0, DATEDIFF(dd, 0, l.LoadDate)) = dct.DateValue
AND l.StateType = 1
AND lc.Main = 1
AND (c.ID = #CustomerID OR (#IncludeChildren = 1 AND c.ParentCustomerID = #CustomerID))
) AS DailyLoadCount
, CONVERT(VARCHAR(6), dct.DateValue, 107) AS DailyLoadDate
, dct.DateValue
FROM DateCTE dct
WHERE
DATEPART(DW, dct.DateValue) NOT IN (1, 7)
AND dct.DateValue NOT IN
(
SELECT HolidayDate FROM Holiday
)
ORDER BY dct.DateValue DESC
) AS S
ORDER BY s.DateValue ASC
RETURN
END
What this SQL is supposed to retrieve is the number of loads per day, for the past #Days that are business days (no weekends/holidays).
I basically just need some help optimizing this so that it doesn't run so slow. (Takes up to 20 seconds per customer, and this will be called over thousands).
Your main problem is just here
WHERE DATEADD(dd, 0, DATEDIFF(dd, 0, l.LoadDate)) = dct.DateValue
It should be
WHERE l.LoadDate >= dct.DateValue
AND l.LoadDate < dct.DateValue +1
Create composite indexs on Load(LoadDate, ID) and Load(ID, LoadDate) and drop the one that does not get used in the query plan.
You should show the query plan whenever you are asking questions about performance. To view the query plan, run the query inside the function on its own using variables for the input parameters. From the menu in SSMS, enable the option "Query -> Include Actual Execution Plan"
Since you don't have enough rep to post images, you can reveal the text plan as follows. Provide some sensible parameters in the first SELECT statement.
set showplan_text on;
Then, run the below in TEXT mode, i.e. press Ctrl-T then Ctrl-E.
DECLARE
#CustomerID INT
, #StartDate DATETIME
, #Days INT
, #IncludeChildren BIT
SELECT
#CustomerID = 1
, #StartDate = '20110201'
, #Days = 10
, #IncludeChildren = 1
DECLARE #TableOfValues TABLE
(
RowID SMALLINT IDENTITY(1,1)
, DailyLoadCount INT
, DailyLoadDate VARCHAR(6)
, FullDate DATETIME
)
DECLARE #MaxDate DATETIME;
SET #MaxDate = DATEADD(dd, #Days * -1.7, DATEDIFF(dd, 0, #StartDate));
WITH DateCTE AS
(
SELECT DATEADD(dd, 0, DATEDIFF(dd, 0, #StartDate)) AS DateValue
UNION ALL
SELECT DATEADD(DAY, -1, DateValue)
FROM DateCTE
WHERE DATEADD(DAY, -1, DateValue) > #MaxDate
)
INSERT INTO #TableOfValues
SELECT * FROM
(
SELECT TOP (#Days)
(
SELECT COUNT(*)
FROM dbo.[Load] l WITH (NOLOCK)
JOIN dbo.LoadCustomer lc WITH (NOLOCK)
ON lc.LoadID = l.ID
JOIN dbo.Customer c WITH (NOLOCK)
ON c.ID = lc.CustomerID
WHERE DATEADD(dd, 0, DATEDIFF(dd, 0, l.LoadDate)) = dct.DateValue
AND l.StateType = 1
AND lc.Main = 1
AND (c.ID = #CustomerID OR (#IncludeChildren = 1 AND c.ParentCustomerID = #CustomerID))
) AS DailyLoadCount
, CONVERT(VARCHAR(6), dct.DateValue, 107) AS DailyLoadDate
, dct.DateValue
FROM DateCTE dct
WHERE
DATEPART(DW, dct.DateValue) NOT IN (1, 7)
AND dct.DateValue NOT IN
(
SELECT HolidayDate FROM Holiday
)
ORDER BY dct.DateValue DESC
) AS S
ORDER BY s.DateValue ASC
SELECT * FROM #TableOfValues
Edit the plan into your question
You should use an inline UDF instead (right now you are actually using a temp table)
See http://msdn.microsoft.com/en-us/library/ms189294.aspx
Or convert it into a view instead.
Correlated subqueries run row-by-row, do not use them. Use a join or a join to a derived table instead. You also need to make sure any where clauses can take advantage of the indexing. Search on saragble queries to see what kinds of things cannot use indexes and what can be done to make it use an index.