I've been working with SQL for a little time so fairly new but have been catching on very quick. I have this very intense query I need to create for a report - I have this in excel and use IF statements and works perfectly.
Here's what I have and need:
I have one table with multiple columns containing dates.
One 'Raving Fan Name' could have more than one date. These are the possibilities / example:
RavingFan ID 1 = FU Date + Testimonial Date + Bonus Date
RavingFan ID 2 = Referral Date + Signed Date
RavingFan ID 3 = Testimonial Date
I need to pull data from each column containing a date filter (of a rolling 6 months) I've read multiple select select statements. This is what I have but it tells me I need a EXISTS - hopefully someone can help!!
SELECT
(SELECT
rf.Raving_Fan_ID,
rf.Raving_Fan_Name,
cr.Contact_Role_Name,
emp.Emp_Name,
rf.FU_Detail,
rf.FU_Date,
rf.FU_Point,
rf.Bonus_Date,
rf.Bonus_Point
FROM Raving_Fans AS rf
LEFT JOIN Employees AS emp ON rf.Emp_ID = emp.Emp_ID
LEFT JOIN Contact_Role AS cr ON rf.Contact_Role_ID = cr.Contact_Role_ID
WHERE rf.FU_Date BETWEEN DATEADD(day,-181,getdate()) AND DATEADD(day,0,getdate())
)
(SELECT
rf.Raving_Fan_ID,
rf.Raving_Fan_Name,
cr.Contact_Role_Name,
emp.Emp_Name,
rf.Test_Detail,
rf.Test_Date,
rf.Test_Point,
rf.Bonus_Date,
rf.Bonus_Point
FROM Raving_Fans AS rf
LEFT JOIN Employees AS emp ON rf.Emp_ID = emp.Emp_ID
LEFT JOIN Contact_Role AS cr ON rf.Contact_Role_ID = cr.Contact_Role_ID
WHERE rf.Test_Date BETWEEN DATEADD(day,-181,getdate()) AND DATEADD(day,0,getdate())
)
(SELECT
rf.Raving_Fan_ID,
rf.Raving_Fan_Name,
cr.Contact_Role_Name,
emp.Emp_Name,
rf.Ref_Detail,
rf.Ref_Date,
rf.Ref_Point,
rf.Signed_Date,
rf.Signed_Point,
rf.Bonus_Date,
rf.Bonus_Point
FROM Raving_Fans AS rf
LEFT JOIN Employees AS emp ON rf.Emp_ID = emp.Emp_ID
LEFT JOIN Contact_Role AS cr ON rf.Contact_Role_ID = cr.Contact_Role_ID
WHERE rf.Ref_Date BETWEEN DATEADD(day,-181,getdate()) AND DATEADD(day,0,getdate())
)
I'm having a hard time wrapping my head around this. Is there an easier way to do this? Any help is appreciated.
This is how it is done, If you want to pull certain criteria from multiple columns.
SET NOCOUNT ON;
SELECT
rf.Raving_Fan_ID,
rf.Raving_Fan_Name AS "Raving Fan",
cr.Contact_Role_Name AS "Contact Type",
emp.Emp_Name AS "TCS Employee",
rf.FU_Detail AS "Follow Ups",
CASE WHEN rf.FU_Date BETWEEN CONVERT(date,DATEADD(month, -6, GETDATE())) and CONVERT(date, GETDATE()) THEN rf.FU_Date ELSE NULL END AS "FU Date",
CASE WHEN rf.FU_Date BETWEEN CONVERT(date,DATEADD(month, -6, GETDATE())) and CONVERT(date, GETDATE()) THEN rf.FU_Point ELSE NULL END AS "FU Point",
rf.Test_Detail AS "Testimonials",
CASE WHEN rf.Test_Date BETWEEN CONVERT(date,DATEADD(month, -6, GETDATE())) and CONVERT(date, GETDATE()) THEN rf.Test_Date ELSE NULL END AS "Test Date",
CASE WHEN rf.Test_Date BETWEEN CONVERT(date,DATEADD(month, -6, GETDATE())) and CONVERT(date, GETDATE()) THEN rf.Test_Point ELSE NULL END AS "Test Point",
rf.Ref_Detail AS "Referrals",
CASE WHEN rf.Ref_Date BETWEEN CONVERT(date,DATEADD(month, -6, GETDATE())) and CONVERT(date, GETDATE()) THEN rf.Ref_Date ELSE NULL END AS "Ref Date",
CASE WHEN rf.Ref_Date BETWEEN CONVERT(date,DATEADD(month, -6, GETDATE())) and CONVERT(date, GETDATE()) THEN rf.Ref_Point ELSE NULL END AS "Ref Point",
CASE WHEN rf.Signed_Date BETWEEN CONVERT(date,DATEADD(month, -6, GETDATE())) and CONVERT(date, GETDATE()) THEN rf.Signed_Date ELSE NULL END AS "Signed Date",
CASE WHEN rf.Signed_Date BETWEEN CONVERT(date,DATEADD(month, -6, GETDATE())) and CONVERT(date, GETDATE()) THEN rf.Signed_Point ELSE NULL END AS "Signed Point",
CASE WHEN rf.Bonus_Date BETWEEN CONVERT(date,DATEADD(month, -6, GETDATE())) and CONVERT(date, GETDATE()) THEN rf.Bonus_Date ELSE NULL END AS "Bonus Date",
CASE WHEN rf.Bonus_Date BETWEEN CONVERT(date,DATEADD(month, -6, GETDATE())) and CONVERT(date, GETDATE()) THEN rf.Bonus_Point ELSE NULL END AS "Bonus Point",
(CASE WHEN rf.Ref_Date BETWEEN CONVERT(date,DATEADD(month, -6, GETDATE())) and CONVERT(date, GETDATE()) THEN rf.Ref_Point ELSE 0 END +
CASE WHEN rf.Signed_Date BETWEEN CONVERT(date,DATEADD(month, -6, GETDATE())) and CONVERT(date, GETDATE()) THEN rf.Signed_Point ELSE 0 END +
CASE WHEN rf.FU_Date BETWEEN CONVERT(date,DATEADD(month, -6, GETDATE())) and CONVERT(date, GETDATE()) THEN rf.FU_Point ELSE 0 END +
CASE WHEN rf.Test_Date BETWEEN CONVERT(date,DATEADD(month, -6, GETDATE())) and CONVERT(date, GETDATE()) THEN rf.Test_Point ELSE 0 END +
CASE WHEN rf.Bonus_Date BETWEEN CONVERT(date,DATEADD(month, -6, GETDATE())) and CONVERT(date, GETDATE()) THEN rf.Bonus_Point ELSE 0 END) AS "Total Points"
FROM [dbo].[Raving_Fans] AS rf
LEFT JOIN Employees AS emp ON rf.Emp_ID = emp.Emp_ID
LEFT JOIN Contact_Role AS cr ON rf.Contact_Role_ID = cr.Contact_Role_ID
WHERE (rf.FU_Date between CONVERT(date,DATEADD(month, -6, GETDATE())) and CONVERT(date, GETDATE()))
OR (rf.Test_Date between CONVERT(date,DATEADD(month, -6, GETDATE())) and CONVERT(date, GETDATE()))
OR (rf.Ref_Date between CONVERT(date,DATEADD(month, -6, GETDATE())) and CONVERT(date, GETDATE()))
OR (rf.Signed_Date between CONVERT(date,DATEADD(month, -6, GETDATE())) and CONVERT(date, GETDATE()))
OR (rf.Bonus_Date between CONVERT(date,DATEADD(month, -6, GETDATE())) and CONVERT(date, GETDATE()))
AND(emp.Emp_Name LIKE '%' +#Emp_Name+ '%' OR #Emp_Name IS NULL)
ORDER BY emp.Emp_Name ASC;
Related
I'm trying to return data from the previous day, except for on Monday I want to return data from the previous 3 days. The below seems logical to me, though I'm getting the error of Incorrect syntax near '='.
Any idea what I'm missing?
*Dates stored in datetime hence the CONVERT functions.
WHERE
CASE WHEN DATEPART(DW,GETDATE()) IN ('1')
THEN (CONVERT(DATE,EV.EVENT_DATE) = CONVERT(DATE,DATEADD(D,-3,GETDATE())))
ELSE (CONVERT(DATE,EV.EVENT_DATE) = CONVERT(DATE,DATEADD(D,-1,GETDATE())))
END
SQL Server does not support boolean expressions like this.
You can express this without the case, which is generally preferable:
WHERE ( DATEPART(WEEKDAY, GETDATE()) = 1 AND CONVERT(DATE, EV.EVENT_DATE) = CONVERT(DATE, DATEADD(DAY, -3, GETDATE()))
) OR
( DATEPART(WEEKDAY, GETDATE()) <> 1 AND CONVERT(DATE, EV.EVENT_DATE) = CONVERT(DATE, DATEADD(DAY, -1, GETDATE()))
)
EDIT:
If you want the weekend dates, then use inequalities. Assuming event_dates are not in the future:
You'll notice that I spelled out the date parts. I find this a better practice than trying to remember/figure out what a particular abbreviation might mean.
WHERE ( DATEPART(WEEKDAY, GETDATE()) = 1 AND CONVERT(DATE, EV.EVENT_DATE) >= CONVERT(DATE, DATEADD(DAY, -3, GETDATE()))
) OR
( DATEPART(WEEKDAY, GETDATE()) <> 1 AND CONVERT(DATE, EV.EVENT_DATE) >= CONVERT(DATE, DATEADD(DAY, -1, GETDATE()))
)
I am getting average values for different past 3, 6 and 10 months.From following queries
select SUM(GrossAmount)/10 as Averageten
FROM Table
WHERE CreatedDate >= DATEADD(MONTH, -10, GETDATE())
select SUM(GrossAmount)/6 as Averagesix
FROM Table
WHERE CreatedDate >= DATEADD(MONTH, -6, GETDATE())
select SUM(GrossAmount)/3 as Averagethree
FROM Table
WHERE CreatedDate >= DATEADD(MONTH, -3, GETDATE())
I get three different values for example:
1200.22
2300.22
4500
I want to get the average of those three values like this
(1200.22 + 2300.22 + 4500) / 3
How can I add values from these separate queries.
Use union to merge three queries and then do average
select avg(Averageten)
from
(select SUM(GrossAmount)/10 as Averageten
FROM Table
WHERE CreatedDate >= DATEADD(MONTH, -10, GETDATE())
union
select SUM(GrossAmount)/6
FROM Table
WHERE CreatedDate >= DATEADD(MONTH, -6, GETDATE())
union
select SUM(GrossAmount)/3
FROM Table
WHERE CreatedDate >= DATEADD(MONTH, -3, GETDATE())
)a
OR you can use conditional aggregation to find the values as you query is from same table with different condition
select ((sum(case when CreatedDate >= DATEADD(MONTH, -10, GETDATE()) then GrossAmount end)/10)
+(sum(case when CreatedDate >= DATEADD(MONTH, -6, GETDATE()) then GrossAmount end)/6)
+(sum(case when CreatedDate >= DATEADD(MONTH, -3, GETDATE()) then GrossAmount end)/3))/3
from tablename
Use conditional aggregation.
SELECT
(
SUM(CASE WHEN CreatedDate >= DATEADD(MONTH, -10, GETDATE()) THEN GrossAmount END) / 10 +
SUM(CASE WHEN CreatedDate >= DATEADD(MONTH, -6, GETDATE()) THEN GrossAmount END) / 6 +
SUM(CASE WHEN CreatedDate >= DATEADD(MONTH, -3, GETDATE()) THEN GrossAmount END) / 3
) / 3 AS [10, 6, 3 Average]
FROM Table
WHERE CreatedDate >= DATEADD(MONTH, -10, GETDATE()) -- this covers all three cases
Basically, when the report is run, I'd like to display YTD data; unless, it is January, then, I want to display all of last year.
I've been attempting to put this in my where statement, using case or iif. In both cases, I get the same error: Msg 102, Level 15, State 1... Incorrect syntax near 'between'.
SELECT
name,
owner,
duedate,
submitteddate
FROM Table
WHERE submitteddate IS NOT NULL AND
CASE WHEN MONTH(GETDATE()) = 1
THEN submitteddate between DATEADD(YEAR, DATEDIFF(YEAR, '19000101', GETDATE()) - 1 , '19000101') AND DATEADD(d, -1, DATEADD(YEAR, DATEDIFF(YEAR, '19000101', GETDATE()), '19000101'))))
ELSE submitteddate between DATEADD(yy, DATEDIFF(yy, 0, GETDATE()), 0) AND GETDATE()))
end
It seems like related to usage of the bracelets. please try like below:
SELECT
name,
owner,
duedate,
submitteddate
FROM Table
WHERE submitteddate IS NOT NULL AND
CASE WHEN MONTH(GETDATE()) = 1
THEN submitteddate between DATEADD(YEAR, DATEDIFF(YEAR, '19000101', GETDATE()) - 1 , '19000101') AND DATEADD(d, -1, DATEADD(YEAR, DATEDIFF(YEAR, '19000101', GETDATE()), '19000101'))
ELSE submitteddate between DATEADD(yy, DATEDIFF(yy, 0, GETDATE()), 0) AND GETDATE()
end
....WHERE YEAR(submitteddate) = YEAR(GETDATE())
- CASE WHEN MONTH(GETDATE()) = 1 THEN 1 ELSE 0 END
How about
WHERE
submitteddate >=
IIF(MONTH(GETDATE()) = 1, DATEADD(Year, -1, GETDATE()), '1900-01-01')
AND submitteddate <= GETDATE();
Or by using a variable
DECLARE #FromDate DATEIME = (SELECT IIF(MONTH(GETDATE()) = 1, DATEADD(Year, -1, GETDATE()), '1900-01-01'));
SELECT *
FROM Table
WHERE
submitteddate >=
#FromDate
AND submitteddate <= GETDATE();
Rather than using a CASE expression in the WHERE, which isn't SARGable, you would be far better off using variables:
DECLARE #StartDate DATE, #EndDate Date;
SET #StartDate = CASE DATEPART(MONTH,GETDATE()) WHEN 1 THEN DATEADD(YEAR, DATEDIFF(YEAR, 0,GETDATE())-1,0)
ELSE DATEADD(YEAR, DATEDIFF(YEAR,0,GETDATE()),0)
END;
SET #EndDate = DATEADD(YEAR,DATEDIFF(YEAR, 0,#StartDate)+1,0);
--SELECT #StartDate, #EndDate; --Uncomment to check the values, but would break SSRS, as it only reads the first returned dataset.
SELECT [name],
[owner],
duedate,
submitteddate
FROM [Table]
WHERE submitteddate >= #StartDate
AND submitteddate < #EndDate;
Note that there is no need to check if the value of submitteddate is NULL or not. NULL = {expression} will always result in "unknown", which isn't true and thus won't be returned in a data set. Thus if you don't want NULL values, then the IS NOT NULL clause is pointless in a WHERE like:
WHERE [Column] IS NOT NULL
AND [Column] = 1;
The above would return exactly the same rows as:
WHERE [Column] = 1;
I'm trying to check if one of the join_date or date_of_change (date fields) are within the range and count them but I get an error:
sqlserver.jdbc.SQLServerException: The conversion from int to
TIMESTAMP is unsupported.
SUM(CASE WHEN (join_date BETWEEN DATEADD(day, -8, GETDATE()) AND DATEADD(day, -1, GETDATE())) OR (date_of_change BETWEEN DATEADD(day, -8, GETDATE()) AND DATEADD(day, -1, GETDATE())) THEN 1 ELSE 0 END) AS Total
Could someone explain to me what I'm doing wrong.
Original Code:
SELECT DISTINCT mtype, CASE WHEN (join_date BETWEEN DATEADD(day, -8,
GETDATE()) AND DATEADD(day, -1, GETDATE())) OR (date_of_change BETWEEN
DATEADD(day, -8, GETDATE()) AND DATEADD(day, -1, GETDATE())) THEN 1 ELSE 0
END AS Total FROM T0 GROUP BY mype, join_date,date_of_change
As #Alex K has said there could be another statement in the batch causing the problem as there doesn't seem to be any TimeStamp involved in this query.
Answering your last comment about the GROUP BY, you can simplify the query the following way:
SELECT
mtype, COUNT(1) as Total
FROM
T0
WHERE
(join_date BETWEEN DATEADD(day, -8, GETDATE()) AND DATEADD(day, -1, GETDATE()))
OR (date_of_change BETWEEN DATEADD(day, -8, GETDATE()) AND DATEADD(day, -1, GETDATE()))
GROUP BY
mype
But I am afraid that if the error is in a different statement.
I wrote the query again and it worked, must be a typo somewhere
I want to return in the same row the results of a particular measure on different time range.
For instance "Last 30 days", "Last 7 days", "Last 3 days".
On doing that I've initially used the UNION function, and created multiple sub-queries for every time range. The downside of doing that is I'm collecting the same numbers three times, with a consequent increase in running time.
A colleague suggested me to use the CASE function to segment the time range. I've initially thought to implement it as follows:
select tp.Name,
case when pub.Date between DATEADD(day, -31, getdate()) and DATEADD(day, -1, getdate())
then SUM(Impressions) else 0 end 'Last 30 days Impressions',
case when pub.Date between DATEADD(day, -31, getdate()) and DATEADD(day, -1, getdate())
then SUM(Revenue * rler.Rate) else 0 end 'Last 30 days Revenues',
case when pub.Date between DATEADD(day, -8, getdate()) and DATEADD(day, -1, getdate())
then SUM(Impressions) else 0 end 'Last 7 days Impressions',
case when pub.Date between DATEADD(day, -8, getdate()) and DATEADD(day, -1, getdate())
then SUM(Revenue * rler.Rate) else 0 end 'Last 7 days Revenues',
case when pub.Date between DATEADD(day, -4, getdate()) and DATEADD(day, -1, getdate())
then SUM(Impressions) else 0 end 'Last 3 days Impressions',
case when pub.Date between DATEADD(day, -4, getdate()) and DATEADD(day, -1, getdate())
then SUM(Revenue * rler.Rate) else 0 end 'Last 3 days Revenues'
from ...
where ...
group by tp.Name, tp.Kind, pub.Date
order by 'Last 30 days Impressions'
Unfortunately this will return a row for each Name, Kind and Date which is not what I want. The issue I think relies on the pub.Date in the GROUP BY call. What should I do to overcome the issue?
You can't quite implement your colleague's suggestion because the times overlap. You can do non-overlapping ranges, something like this:
select tp.Name,
(case when pub.Date between DATEADD(day, -3, getdate()) and DATEADD(day, -1, getdate())
then 'Last 3 days Impressions'
when pub.Date between DATEADD(day, -7, getdate()) and DATEADD(day, -1, getdate())
then '4-7 days Impressions'
when pub.Date between DATEADD(day, -31, getdate()) and DATEADD(day, -1, getdate())
then '8-31 days Impressions'
else 'Older'
end) as TimeRange,
SUM(Impressions) as NumImpressions,
. . .
from . . .
where . . .
group by tp.Name,
(case when pub.Date between DATEADD(day, -3, getdate()) and DATEADD(day, -1, getdate())
then 'Last 3 days Impressions'
when pub.Date between DATEADD(day, -7, getdate()) and DATEADD(day, -1, getdate())
then '4-7 days Impressions'
when pub.Date between DATEADD(day, -31, getdate()) and DATEADD(day, -1, getdate())
then '8-31 days Impressions'
else 'Older'
end)
I'm answering my own question. The result can be achieve using the following code:
select tp.Name,
sum(case when pub.Date between DATEADD(day, -31, getdate()) and DATEADD(day, -1, getdate())
then Impressions else 0 end) 'Last 30 days Impressions',
sum(case when pub.Date between DATEADD(day, -31, getdate()) and DATEADD(day, -1, getdate())
then (Revenue * rler.Rate) else 0 end) 'Last 30 days Revenues',
sum(case when pub.Date between DATEADD(day, -8, getdate()) and DATEADD(day, -1, getdate())
then Impressions else 0 end) 'Last 7 days Impressions',
sum(case when pub.Date between DATEADD(day, -8, getdate()) and DATEADD(day, -1, getdate())
then (Revenue * rler.Rate) else 0 end) 'Last 7 days Revenues',
sum(case when pub.Date between DATEADD(day, -4, getdate()) and DATEADD(day, -1, getdate())
then Impressions else 0 end) 'Last 3 days Impressions',
sum(case when pub.Date between DATEADD(day, -4, getdate()) and DATEADD(day, -1, getdate())
then (Revenue * rler.Rate) else 0 end) 'Last 3 days Revenues'
from ...
where ...
group by tp.Name, tp.Kind
order by 'Last 30 days Impressions' desc