How to bring some value when result is empty - sql

I have a stored procedure like this:
declare #myVal int
select
t2.short_descr , count(*) as count
FROM
t1
INNER JOIN
t2 ON t1.id = t2.id
where
[date] BETWEEN DATEADD(day, DATEDIFF(day, 0, GETDATE()), 0) and GETDATE())
group by
t2.short_descr
It works good, now I want the procedure to return a result even if it is empty; in that case, I want to return
select #myVal
I tried like this :
declare #myVal int
select
t2.short_descr , count(*) as count
FROM
t1
INNER JOIN
t2 ON t1.id = t2.id
where
[date] BETWEEN DATEADD(day, DATEDIFF(day, 0, GETDATE()), 0) and GETDATE())
group by
t2.short_descr
IF ##ROWCOUNT = 0
select #myVal
but when result is empty stored procedure selects 2 results: empty and #myVal. I want if is empty select just #myVal . How do it ?

You can add EXISTS check like this:
IF EXISTS ( SELECT 1 FROM t1 INNER JOIN t2 ON t1.id = t2.ID
where [date] BETWEEN DATEADD(day,DATEDIFF(day,0,GETDATE()),0) and GETDATE()) )
BEGIN
select t2.short_descr , count(*) as count
FROM t1
INNER JOIN t2 ON t1.id = t2.id
where [date] BETWEEN DATEADD(day,DATEDIFF(day,0,GETDATE()),0) and GETDATE())
group by t2.short_descr
END
ELSE
BEGIN
select #myVal
END

Related

how to count no of records in a temporary table created using WITH clause

I created a stored procedure using sql server and i need to count no of records in a temporary table created using the 'WITH' clause.
I used that temp table one time as an inner join. Apart from that, I want to count no of records in that record temp table and set that value to #SlotCount variable.
I tried it like this(temp table name is cte):
SELECT #SlotCount = COUNT(*) FROM cte
This gives errors because I used temp table twice in a stored procedure. So please help me to solve this. Thank you
Stored Procedure :
ALTER PROCEDURE [dbo].[usp_GetXXXXXXXXXXXXXXXXX]
-- Add the parameters for the stored procedure here
#Starttime DATETIME,
#Endtime DATETIME
AS
BEGIN
DECLARE #SlotCount int
;WITH cte AS ( SELECT #Starttime starttime, DATEADD(MINUTE, 15, #Starttime) endtime
UNION ALL
SELECT endtime, DATEADD(MINUTE, 15, endtime)
FROM cte
WHERE endtime < #Endtime)
--do something for count no of records in cte table and set that value to #SlotCount
select count(a.AVAIL_ID),a.TEACHER_USERNAME
from cte c
INNER JOIN AvailabilityDetail ad ON c.starttime = ad.StartDateTime AND c. endtime = ad.EndDateTime
INNER JOIN AVAILABILITY a ON ad.AVAIL_ID = a.AVAIL_ID
LEFT JOIN TEACHER_BIO b ON a.TEACHER_USERNAME = b.TEACHER_USERNAME
WHERE ad.IsAvailable = 1
AND ad.AvailabilityType = 'N'
AND b.Active = 1
AND b.IsGroupClass = 1
AND b.HIDE_FROM_SCHEDULING = 0
GROUP BY a.AVAIL_ID,a.TEACHER_USERNAME
END
You can store results to temp table and then later return it
DECLARE #SlotCount int
;WITH cte AS ( SELECT #Starttime starttime, DATEADD(MINUTE, 15, #Starttime) endtime
UNION ALL
SELECT endtime, DATEADD(MINUTE, 15, endtime)
FROM cte
WHERE endtime < #Endtime)
select count(a.AVAIL_ID),a.TEACHER_USERNAME
INTO #cte from cte c
INNER JOIN AvailabilityDetail ad ON c.starttime = ad.StartDateTime AND c. endtime = ad.EndDateTime
INNER JOIN AVAILABILITY a ON ad.AVAIL_ID = a.AVAIL_ID
LEFT JOIN TEACHER_BIO b ON a.TEACHER_USERNAME = b.TEACHER_USERNAME
WHERE ad.IsAvailable = 1
AND ad.AvailabilityType = 'N'
AND b.Active = 1
AND b.IsGroupClass = 1
AND b.HIDE_FROM_SCHEDULING = 0
GROUP BY a.AVAIL_ID,a.TEACHER_USERNAME
SELECT * FROM #cte
SET #SlotCount = (SELECT COUNT(*) FROM #cte)

Tsql union in while loop

I am trying to union the same table together with itself while changing some value in the where clause. The problem i have is with the union between the loops. I can not use a table variable since the schema is too complicated to write by hand each time. Temp tables seem to be the way to go but I do not know how to get it to work and the correct syntax.
psuedo code of what I am trying to achieve:
DECLARE #var int, #tempTable
SET #var = someValue
WHILE expressionIncludingVar
#tempTable = SELECT *
FROM someTable
WHERE column = #var
UNION ALL #tempTable
SET #var = someChangeToVar
RETRUN #tempTable
The result of the query should be #tempTable hence the weird "RETURN #tempTable".
Thank you in advance.
EDIT:
Another hardcoded example:
I am trying to unhardcode something like this:
SELECT someAggregateColumns
FROM table
WHERE someDateColumn > #date and < someDateColumn < DATEADD(month, 2, #date)
GROUP BY someColumn
UNION ALL
SELECT someAggregateColumns
FROM table
WHERE someDateColumn > DATEADD(month, 1, #date) and and < someDateColumn < DATEADD(month, 1, DATEADD(month, 3, #date))
GROUP BY someColumn
SELECT someAggregateColumns
FROM table
WHERE someDateColumn = DATEADD(month, 2, #date) DATEADD(month, 1, DATEADD(month, 4, #date))
GROUP BY someColumn
UNION ALL
....etc
Maybe Recursive CTE works for you.
You can try this.
DECLARE #MyTable TABLE(ID INT, ColumnA VARCHAR(10), ColumnB VARCHAR(10))
INSERT INTO #MyTable VALUES
(1,'A', '10'),
(2,'B', '11'),
(3,'C', '12'),
(4,'D', '13'),
(5,'E', '14'),
(6,'F', '15'),
(7,'H', '16')
DECLARE #var INT = 4
;WITH CTE AS (
SELECT * FROM #MyTable WHERE ID = #var
UNION ALL
SELECT T.* FROM CTE INNER JOIN #MyTable T ON CTE.ID - 1 = T.ID
)
SELECT * INTO #tempTable FROM CTE
SELECT * FROM #tempTable
DROP TABLE #tempTable
If the only thing what is different in each cycle is a counter, then why aren't you just write one query including all data?
Instead of WHERE column = #var use WHERE column >= 0 AND column <= #maxVarValue.
If your conditions are more complex, you should consider to have a small (temp) table which contains the columns to be filtered, then just join that table to your source to get the desired result.
According to the comments, you can use a tally table (or numbers table).
Example:
DECLARE #Tally (Number INT);
INSERT INTO #Tally (Number) VALUES (0),(1),(2),(3),(4),(5);
SELECT
someAggregateColumns
FROM
table AGG
INNER JOIN #Tally T
ON AGG.someDateColumn = DATEADD(month, T.Number, #date)
WHERE
T.Number >= 0
AND T.Number <= 3
;
The above query will return the results for the current and the next 3 months.
You can persist a numbers table and re-use it. I usually have one called util.Number.
based in second example what you want is
SELECT someAggregateColumns
FROM table
WHERE someDateColumn IN (
#date,
DATEADD(month, 1, #date),
DATEADD(month, 2, #date),
DATEADD(month, 3, #date)
)
GROUP BY someColumn
Now if you want a range is even easier:
WHERE someDateColumn BETWEEN #date
AND DATEADD(month, 3, #date)
Using a TALLY table and a CROSS APPLY you can generate the Dates to check:
DECLARE #Var INT = 4
DECLARE #Date Date = '2017-01-01'
;WITH Tally
AS
(
SELECT ROW_NUMBER() OVER (ORDER BY Object_Id) -1 AS Num
FROM sys.columns
)
SELECT *
FROM MyTable
CROSS APPLY Tally
WHERE Num < #var AND
MyDate = DATEADD(month, num, #date)

sql server while date not weekend or a specific date

I'm trying to write an sql while loop to increment a date until it doesn't mate a date in two other tables and is not a Saturday or a Sunday.
Something like this
DECLARE #DueDate datetime
SELECT #DueDate = datetime FROM tbl_status WHERE (parent_id = #ComplaintId)
WHILE((SELECT COUNT(date) FROM tbl1 WHERE(date = #DueDate)) > 0 AND (SELECT COUNT(date) FROM tbl2 WHERE(date = #DueDate)) > 0 AND DATEPART(d,#DueDate) = 'Saturday' AND DATEPART(d,#DueDate) = 'Sunday')
BEGIN
#DueDate = DATEADD(d,1,#DueDate)
END
Can anyone help
thanks
As I mentioned in my comment, you are going about this in a very inefficient manner with your while loop.
If you don't have a table of dates to use in a lookup, you can create one with a derived table, otherwise known as a Common Table Expression:
-- Set up the test data:
declare #t1 table (d date);
declare #t2 table (d date);
insert into #t1 values('20161230'),('20170111'),('20170110');
insert into #t2 values('20161225'),('20170105'),('20170106');
-- Declare your DueDate:
declare #DueDate date = '20170105';
-- Use a CTE to build a table of dates. You will want to set the Start and End dates automatically with SELECT statements:
declare #DatesStart date = '20161201';
declare #DatesEnd date = '20170225';
with Tally0 as
(
select x from (values(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) as x(x)
)
,Tally1 as
(
select row_number() over (order by (select null))-1 as rn
from Tally0 t1 -- 10 rows -- Add more CROSS APPLY joins
cross apply Tally0 t2 -- 100 rows -- to get enough rows to cover
cross apply Tally0 t3 -- 1000 rows -- your date range.
)
,Dates as
(
select dateadd(d,t.rn,#DatesStart) as DateValue
from Tally1 t
where t.rn <= datediff(d,#DatesStart,#DatesEnd)
)
select min(d.DateValue) as NextDate -- SELECT the next available Date.
from Dates d
left join #t1 t1
on(d.DateValue = t1.d)
left join #t2 t2
on(d.DateValue = t2.d)
where t1.d is null -- That isn't in either table
and t2.d is null -- and isn't on a Saturday or Sunday.
and datename(weekday,d.DateValue) not in('Saturday','Sunday')
and d.DateValue > #DueDate

what wrong with this script sql?

I have table users with columns ID,USERSID
table :
t_A(ID,usersID,ADATE,priceA,priceB)
t_B(ID,usersID,BDATE,priceA,priceB)
t_C(ID,usersID,CDATE,priceA,priceB)
I'm using this query to get SUM of price from 3 tables for X DATE , and USERSID
declare #id int
set #id = 3 -- for example
SELECT SUM(priceA) as TA, SUM(priceB) as TB
FROM t_A,t_B,t_C
WHERE t_A.USERSID = #id
AND t_B.USERSID = #id
AND t_C.USERSID = #id
AND ADATE >= DATEADD(DAY, 0, DATEDIFF(DAY, 0, getdate()))
AND BDATE >= DATEADD(DAY, 0, DATEDIFF(DAY, 0, getdate()))
AND CDATE >= DATEADD(DAY, 0, DATEDIFF(DAY, 0, getdate()))
this script work only if the USERSID had a row in the three tables otherwise script return nothing
Because if only one table has no USERID = 3 that result always will be empty. Workaround: use option with UNION ALL operator
DECLARE #id int
SET #id = 3
SELECT SUM(x.priceA) as TA, SUM(x.priceB) AS TB
FROM (
SELECT priceA, priceB
FROM t_A
WHERE t_A.USERSID = #id
AND ADATE >= DATEDIFF(d,0,dateadd(d,0,getdate()))
UNION ALL
SELECT priceA, priceB
FROM t_B
WHERE t_B.USERSID = #id
AND BDATE >= DATEDIFF(d,0,dateadd(d,0,getdate()))
UNION ALL
SELECT priceA, priceB
FROM t_C
WHERE t_C.USERSID = #id
AND CDATE >= DATEDIFF(d,0,dateadd(d,0,getdate()))
) x
You can't compare a date column with a datediff. Here are some things you could do:
AND ADATE >= GETDATE()
or:
AND DATEDIFF(d, ADATE, GETDATE()) > 1
You can check the syntax and some examples at MSDN.
I think this is what you need. This way, it will return results as long as one of the tables satisfies the condition:
SELECT SUM(priceA) as TA, SUM(priceB) as TB, SUM(priceC) as TC
FROM t_A
FULL JOIN t_B
FULL JOIN t_C
WHERE t_A.USERSID = #id
AND t_B.USERSID = #id
AND t_C.USERSID = #id
AND ADATE >= DATEDIFF(d,0,dateadd(d,0,getdate()))
AND BDATE >= DATEDIFF(d,0,dateadd(d,0,getdate()))
AND CDATE >= DATEDIFF(d,0,dateadd(d,0,getdate()))

Incrementing a counter for dateadd

I'm trying to increase the time between dates by a set amount. For example, I want to add two months to the time between date 1,2 and 3. I'm having trouble incrementing my 'date counter'...
DECLARE #monthDiff int
SET #monthDiff = 1;
UPDATE [Table1]
SET [Date] = DATEADD(MONTH, (SET #monthDiff = #monthDiff + 1), [Date])
WHERE [ID] IN
(
SELECT [ID]
FROM [Table2]
WHERE [Description] = 'HE'
);
An example might help...
Original dates:
01/04/1984
01/05/1984
01/06/1984
New dates:
01/04/1984
01/06/1984
01/08/1984
Any ideas?
I'm using SQLServer 2005.
Thanks.
;WITH cte AS
(
SELECT t1.ID,
t1.[Date],
ROW_NUMBER() OVER (PARTITION BY t1.ID ORDER BY [Date]) AS RN
FROM Table1 t1
JOIN Table2 t2
ON t1.ID = t2.ID
WHERE t2.[Description] = 'HE'
)
UPDATE CTE
SET [Date] = DATEADD(MONTH, RN-1, [Date])
this should work, although only if each original date in your table is unique. I've called the column mydate because I don't think date is a legal (or sensible) name for a column. This could be easier and safer if you've got some kind of ID column. then we would use that for the cursor rather than the date
declare #numberOfMonthsToAdd int
declare #currentDate dateTime
set #numberOfMonthsToAdd = 0
declare myCursor cursor for
select [mydate] from Table1
open myCursor
while ##fetch_Status<>-1
begin
fetch next from myCursor into #currentDate
update Table1 set [mydate] = DATEADD(month,#numberOfMonthsToAdd, [mydate]) where [mydate] = #currentDate
set #numberOfMonthsToAdd = #numberOfMonthsToAdd + 1
end
close mycursor
deallocate mycursor
From your example, it seems you want to change the dates relative to a base date:
declare #basedate datetime
select #basedate = min([Date]) FROM Table1 WHERE ...
UPDATE [Table1]
SET [Date] = DATEADD(MONTH, DATEDIFF(MONTH, #basedate, [Date]) * 2, [Date])
WHERE ...