Create a new column in a SQL query with IF/ELSE logic? - sql

I'm working on a query that pulls a list of people who visited a certain location. Part of the location's policy is that if a person hasn't visited within 3 years, they're no longer an active member and would have to re-establish their membership. Normally I just paste my query results into Excel and add a column with a formula that looks at the last visit date and flags whether the person is active or not, but I thought I might try to add that calculation directly to my query and have SQL Server do the work for me. Problem is, I'm not sure about the syntax.
I'd like my end result to look something like this (I typically have my Excel formula just look 3 years back from the date I'm creating the report, so for the purposes of this example, we're looking 3 years back from 12/17/2019):
PersonID LastVisit Active
-------------------------------------
1001 2019-12-01 YES
1002 2014-07-24
1003 2016-12-31 YES
1004 2018-10-12 YES
1005 2016-02-04
1006 2017-09-20 YES
If I'm understanding right from some of the research I've tried to do so far, this would require a CASE statement.
SELECT
PersonID,
LastVisit,
CASE [--not sure what, if anything, goes here--]
WHEN LastVisit > DATEADD(yy,-3,GETDATE()) THEN 'YES'
END AS Active
FROM PersonInfo
ORDER BY PersonID
As it stands now, I've got a couple of syntax errors: incorrect syntax near '>' and incorrect syntax near 'THEN'. Am I at least on the right track? What do I need to do to get this logic to work?

This syntax should work:
(CASE WHEN LastVisit > DATEADD(year, -3, GETDATE()) THEN 'YES'
END) AS Active
By the way, this is called a case expression in SQL.

The only actual issue I see with your code is your square brackets. You start the comment after your first square bracket in the case statement. If you remove the unnecessary stuff or start the comment earlier it should work.
Removing the comment entirely:
SELECT
PersonID,
LastVisit,
CASE
WHEN LastVisit > DATEADD(yy,-3,GETDATE()) THEN 'YES'
END AS Active
FROM PersonInfo
ORDER BY PersonID
Alternatively just start your comment earlier
SELECT
PersonID,
LastVisit,
CASE --[not sure what, if anything, goes here--]
WHEN LastVisit > DATEADD(yy,-3,GETDATE()) THEN 'YES'
END AS Active
FROM PersonInfo
ORDER BY PersonID

Related

SQL filtering activity after certain event

I am struggling with a SQL query.
My query looks something like this:
Select
Count(user-id),
sum(distinct(date),
Sum(characters-posted)
From (
Select
Date,
User-Id,
Session-Id,
Characters—posted,
Variant-id
From database-name
Where date between ‘2022-09-01’ and ‘2022-09-31’)
This works ok. But, there is another field in the table “mailing-list”, which is just 0 or 1. I want to only get activity for members from the date when they join the mailing list onwards, even if they then leave the list, so can’t just do “where mailing-list=1”.
How can I do this?
It's not obvious what works fine for you as it seems to be uncommon to sum dates, given it is a regular date format. Are you trying to get number of active dates? as for the bottom question you might.
As for your buttom line quesiton, it seems that you might want to use a cte or subselect in a join.
your query...
from db_name dbn
inner join (select user_id, min(date) date from database_name
where mailing_list = 1 group by 1) start_date
on start_date.user_id = dbn.user_id
and start_date.date <= dbn.date
That way you're only getting activity starting from the first time your users join the mailing list.
But I still think you have an error in your final query, check it out.

In tsql how to select records based on even or uneven dates

I am trying to figure out how to be able to select records based on even or uneven dates.
I have a table with 4 columns and one has the sign up date and I would like to segment them into two groups based on their sign up dates (using the day as the denominator). So 12/4/2013 would be in the even and 4/3/2012 in the uneven.
I am not sure how to construct this query, I was looking at the datepart but wasn't sure if there is something more straight forward.
thanks
SELECT signed_on, DAY(signed_on) % 2 AS uneven
FROM YourTable
uneven will be either 0 or 1
SELECT DAY('2013-01-03') % 2 -- 1
SELECT DAY('2013-01-02') % 2 -- 0
If you want to name your column even rather than uneven you could just inverse the result.
SELECT signed_on, POWER(DAY(signed_on) % 2 - 1, 2) AS even
FROM YourTable
HINT (for now unless you can show you've tried something yourself) You could do something like DATEPART(day, date) % 2 with a case statement (case statement isn't necessary, but could be if you want to easily go between even and uneven without changing the query of course depending on your environment).
DATEPART(dd, your_date) should give you the date part of your date and then use % to find if it is even or not in the WHERE clause.
I believe something like this should be straight forward -
SELECT COL,CASE WHEN DAY(COL)%2=0 THEN 'EVEN' ELSE 'UNEVEN' END AS [EVEN_UNEVEN]
FROM TEST
Sample output from my sample table-
COL EVEN_UNEVEN
2014-01-09 22:39:51.203 UNEVEN
2014-01-10 22:39:51.210 EVEN
2014-01-12 22:39:51.210 EVEN
2014-01-13 22:39:51.213 UNEVEN

Using iif to mimic CASE for days of week

I've hit a little snag with one of my queries. I'm throwing together a simple chart to plot a number of reports being submitted by day of week.
My query to start was :
SELECT Weekday(incidentdate) AS dayOfWeek
, Count(*) AS NumberOfIncidents
FROM Incident
GROUP BY Weekday(incidentdate);
This works fine and returns what I want, something like
1 200
2 323
3 32
4 322
5 272
6 282
7 190
The problem is, I want the number returned by the weekday function to read the corresponding day of week, like case when 1 then 'sunday' and so forth. Since Access doesn;t have the SQL server equivalent that returns it as the word for the weekday, I have to work around.
Problem is, it's not coming out the way I want. So I wrote it using iif since I can't use CASE. The problem is, since each iif statement is treated like a column selection (the way I'm writing it), my data comes out unusable, like this
SELECT
iif(weekday(incidentdate) =1,'Sunday'),
iif(weekday(incidentdate) =2,'Monday')
'so forth
, Count(*) AS NumberOfIncidents
FROM tblIncident
GROUP BY Weekday(incidentdate);
Expr1000 Expr1001 count
Sunday 20
Monday 106
120
186
182
164
24
Of course, I want my weekdays to be in the same column as the original query. Halp pls
Use the WeekdayName() function.
SELECT
WeekdayName(Weekday(incidentdate)) AS dayOfWeek,
Count(*) AS NumberOfIncidents
FROM Incident
GROUP BY WeekdayName(Weekday(incidentdate));
As BWS Suggested, Switch was what I wanted. Here's what I ended up writing
SELECT
switch(
Weekday(incidentdate) = 1, 'Sunday',
Weekday(incidentdate) = 2,'Monday',
Weekday(incidentdate) = 3,'Tuesday',
Weekday(incidentdate) = 4,'Wednesday',
Weekday(incidentdate) = 5,'Thursday',
Weekday(incidentdate) = 6,'Friday',
Weekday(incidentdate) = 7,'Saturday'
) as DayOfWeek
, Count(*) AS NumberOfIncidents
FROM tblIncident
GROUP BY Weekday(incidentdate);
Posting this here so there's actual code for future readers
Edit: WeekdayName(weekday(yourdate)) as HansUp said it probably a little easier :)
check this previous post:
What is the equivalent of Select Case in Access SQL?
Why not just create a 7 row table with day number & day name then just join to it?

Retrieve data using between some date range

I have the following table in my database
Membership
ComapanyId
IsMember
JoinedDate
ExpiryDate
RejoinDate
LeavingDate
I am using the following query to return all the members as for 2011-01-31
select * from MEMBERSHIP
where (JoinedDate < '2011-01-31' or RejoinDate < '2011-01-31') and IsMember=1
My problem is it doesnt tally with the figures my manager has. Am I doing something wrong?
The problem is that IsMember is currently whether they are a member, not whether they were a member on 2011-01-31. So, your query is really answering the question: "Which members who were active today joined or last rejoined before 2011-01-31?"
For instance, someone who starts on 2011-01-30 and quits on 2011-02-01 would not count as a member in your query, but would be a member on that date.
The most accurate answer is to look in a transaction table for memberships, where you have joins and quits in the table.
Barring that, the following probably gets close enough:
select *
from MEMBERSHIP
where '2011-01-31' between JoinedDate and LeaveDate
Shouldn't you remove the "IsMember = 1" statement as you want to list users that were members before 2011-01-31 but are not members anymore? And maybe you should use '<=' if you want to include the 31th.
Also what is the default value of RejoinDate? If it is null it could have an influence on your WHERE statement...
The problem is that your date is implicitly treated as midnight of 2011-01-31 ('2011-01-31 00:00:00'), so any activity on that day is not included. Try using < '2011-02-01' instead, so that all of the activity on the 31st is included.
You clould use something like this:
JoinedDate <= CONVERT(Date, '2011-01-31')

Need to decide between a trigger, CASE, END-ELSE to write to a table & DATEDIFF()

Bear with me here. I used the script found at:
http://sqlfool.com/2008/11/replication-monitor/
I want to test to see if an entry been made from the server over the last 30 minutes?
If the answer is NO, then write that entry to a different table and possibly alert us.
The following query me the difference in minutes between right now and the very last entry for the server Test1 under 'monitorDate', a datetime field.
SELECT TOP 1 DATEDIFF (minute, (SELECT TOP 1 (SELECT MAX(monitorDate)
FROM dba_replicationMonitor)), GETDATE())
FROM MASTER.dbo.dba_replicationMonitor
WHERE publicationName = 'Test1'
I can't figure out how to say 'if that number returned is more than 5, pass the serverName and monitorDate to a different table.
Any suggestions to point the way would be greatly appreciated. Thanks.
Couldn't you just derive your results and insert them if they match your needs?
INSERT INTO WHATEVERTABLE (serverfield, datefield)
SELECT result.server, result.date
FROM (YOURQUERY) result
WHERE result.yourresult > 5