Stuck on what is a simple query - sql

If i have 2 tables one for people and one for holidays. Everytime someone goes on holiday the date gets entered in the holiday table. How would I query this so it shows the person name from the persons table if they have been on more then say 2 holidays between 1st of jan 2010 and the 6th of june 2010? This seems simple but I cant seem to do it.

If all you want is the list of names of people taking 2 or more days between those two dates:
SELECT people.name
FROM people
WHERE EXISTS (
SELECT count(*)
FROM days_taken
WHERE people.person_id=days_taken.person_id AND
days_taken.vacation_date BETWEEN date1 AND date2
HAVING count(*)>=2
)
If you want the name and the number of days:
SELECT people.name,count(*)
FROM people JOIN days_taken ON people.person_id=days_taken.person_id
WHERE days_taken.vacation_date BETWEEN date1 AND date2
GROUP BY people.name
HAVING count(*)>=2

SELECT people.name, COUNT(*) c
FROM people INNER JOIN holidays
ON people.user_id = holidays.user_id
WHERE holidays.departure_date BETWEEN date1 AND date2
GROUP BY people.name
HAVING c > 2

SELECT p1.name, p2.num_holidays
FROM people p1
INNER JOIN
(
SELECT people.user_id, COUNT(*) as num_holidays
FROM people
INNER JOIN holidays ON (people.user_id = holidays.user_id)
WHERE holidays.departure_date BETWEEN date1 AND date2
GROUP BY people.user_id
HAVING COUNT(*) > 2
)p2 ON (p2.user_id = p1.user_id)

For SQL Server 2005 onwards, you can use the analytical function Count() OVER
select p.*, h.C
from person p inner join
(
select distinct person_id, C = COUNT(*) over (partition by person_id)
from holiday
where holiday_date between '20100101' and '20100606'
) h on h.person_id = p.person_id and h.C >= 2

Related

Select where MAX(DATE) between X and X

I'm trying to select only patients, who had their LAST appointment in the year 2015. The ideal thing would look like this:
Select person.name, person.surname
inner join patient on patient.pat_id=person.per_id
inner join appointment on appointment.pat_id=patient.pat_id
where MAX(appointment.date) between '31.12.2014'and '01.01.2016'
But of MAX isn't allowed in WHERE clause. What's the best workaround?
You are close:
Select p.name, p.surname
from person p inner join
patient pa
on pa.pat_id = p.per_id join
appointment a
on a.pat_id = pa.pat_id
group by p.per_id, p.name, p.surname
having max(a.date) >= date '2015-01-01' and
max(a.date) < date '2016-01-01';
Notes:
You need group by.
Note that I'm including per_id in the group by, because different people can have the same name.
Date constants can be introduced with the date keyword.
Do not use between with dates; this is particularly true in Oracle where a date column can have a time component.

INNER JOIN inside Subquery SQL

I'm having problem inserting inner join inside subquery like this:
SELECT * FROM (
SELECT *,
(DATEDIFF(day, Date, CurrentDate)) AS Age
FROM Order_Member
)sub
WHERE Age > 7
Which in this case it produces output like this:
OrderID Date CurrentDate Quantity Total Age
O01 2017-05-22 2017-05-31 3 150 9
O02 2017-05-23 2017-05-31 2 160 8
Which is running correctly which only shows age > 7, but I cant put another table into the subquery using INNER JOIN.
Any Help?
Sure you can, just add an inner join clause to the subquery:
SELECT * FROM (
SELECT *,
(DATEDIFF(day, Date, CurrentDate)) AS Age
FROM Order_Member om
INNER JOIN Other_Table ot on om.id = ot.id -- Here
)sub
WHERE Age > 7
After reviewing your question and query I don't think even your require sub query
SELECT om.*, ot.*, (DATEDIFF(day, Date, CurrentDate)) Age
FROM Order_Member om
INNER JOIN Other_Table ot on om.id = ot.id -- Here
WHERE (DATEDIFF(day, Date, CurrentDate)) >7
A part from this you have other option like Cross Apply as well.
u can use table1, table2 instead of sub

Group by Month, return 0 if no record found

I want to fetch records from database table for last 12 months. Here is what I tried so far.
SELECT COUNT(s.id), date_part('month', s.viewed_at) month_number
FROM statistics_maps_view as s
INNER JOIN maps as m
ON s.maps_id=m.id Where m.users_id = $users_id group by month_number ORDER BY month_number DESC LIMIT 12
I know It'll group the records month wise. but is there a way to add Count = 0 if there is no record for a particular month?
The group by clause will not create entries where there's no data, as you've seen. What you could do is left join this entire result with another result set that has all the entries you want - e.g., one you dynamically generate with generate_series:
SELECT generate_series AS month_number, cnt
FROM GENERATE_SERIES(1,12) g
LEFT JOIN (SELECT COUNT(s.id) AS cnt,
DATE_PART('month', s.viewed_at) AS month_number
FROM statistics_maps_view s
INNER JOIN maps m ON s.maps_id = m.id
WHERE m.users_id = $users_id
GROUP BY month_number) s ON g.generate_series = s.month_number
ORDER BY 1 ASC

Query based on Count, Time frame, and location

Ok so I need to write a query that I am probably making much more complicated than it needs to be but I could use some help.
I need to select records of clients that have not been seen for a year or longer, have seen us more than once but can be only once if it is not at certain locations.
So what I have so far is:
WITH CTE AS
(
SELECT
client_id,
location_id,
employee_id,
create_timestamp,
ROW_NUMBER() OVER(PARTITION BY person_id ORDER BY create_timestamp DESC) AS ROW
FROM
client_Appointment
)
SELECT
c.client_id,
COUNT(*)
FROM
CTE AS ce
INNER JOIN person AS c
ON p.person_id= ce.client_id
INNER JOIN employee_mstr AS em
ON em.employee_id = ce.empoyee_id
INNER JOIN location_mstr AS lm
ON lm.location_id = ce.location_id
WHERE
ce.create_timestamp <= CONVERT(VARCHAR(10), DATEADD(Year,-1,GETDATE()), 120)
GROUP BY
p.person_id
HAVING
COUNT(*) > 1
I'm unsure where to go from here. Also this does not get me all the info I need and if I add that information to the select clause I have to use it in group by which means I don't get all the needed records.
Thanks
So you want only clients who have not been seen in a year or more,
then clients that have either one visit NOT at certain locations OR more than one visit. Did I get that right?
Note: Just replace (VALUES(1),(2),(3)) with your table name
WITH CTE_visits
AS
(
SELECT
c.client_id,
COUNT(*) AS total_visits,
SUM(
CASE
WHEN ce.location_id IN (SELECT ID FROM (VALUES(1),(2),(3)) AS A(ID)) THEN 0 --so when it is a certain location then do NOT count it
ELSE 1 --if it is not at the certain locations, then count it
END
) AS visits_not_at_certain_locations
FROM
client_Appointment AS ce
INNER JOIN person AS c
ON p.person_id= ce.client_id
INNER JOIN employee_mstr AS em
ON em.employee_id = ce.empoyee_id
INNER JOIN location_mstr AS lm
ON lm.location_id = ce.location_id
CROSS APPLY(SELECT client_id, MAX(create_timestamp) last_visit FROM client_Appointment WHERE client_id = ce.client_id GROUP BY client_id) CA --find most recent visit for each client_id
WHERE
ce.create_timestamp <= CONVERT(VARCHAR(10), DATEADD(Year,-1,GETDATE()), 120) --remember this only counts visits over a year ago
AND last_visit <= CONVERT(VARCHAR(10), DATEADD(Year,-1,GETDATE()), 120) --says only return client_id's who's last visit is more than a year ago
GROUP BY
p.person_id
)
SELECT *
FROM CTE_visits
WHERE visits_not_at_certain_locations = 1 --seen once NOT at certain locations
OR total_visits > 1 --seen more than once at any location

SQL MAX() value across 2 or more queries

This seems like a basic action in SQL, but it has me stumped.
I have about 2 different subqueries, each grouped by LOCATION_ID that contain a date column. For example, one query includes a listing of WORKORDER records while another query pulls records from the NOTE table. Both of these queries includes a join to the LOCATION table allowing me to group by LOCATION_ID.
My goal is to pull the latest date of contact at that particular location and that can be in the form of a workorder, note date, followup date, etc. which are stored in different tables. So ideally I would have a query grouped by LOCATION_ID that shows the latest date of contact for that location.
I would post SQL but I don't have anything that is currently working for me. Any ideas on how to approach this type of scenario?
Thanks!
SELECT
L.LOCATION_ID, Max(MaxDate)
FROM
LOCATION AS L
LEFT JOIN
(SELECT
LOCATION_ID, Max(dbo.LeadNote.NoteDate) AS MaxDate
FROM
LeadNote
INNER JOIN
LOCATION ON LeadNote.LOCATION_ID = LOCATION.LOCATION_ID
GROUP BY
LOCATION_ID) T1 ON L.LOCATION_ID = T1.CONTACTLOCATION_LOCATION_ID
LEFT JOIN
(SELECT
LOCATION_ID, Max(dbo.WORKORDER.WORKORDER_DATECREATED) AS MaxDate
FROM
WORKORDER
INNER JOIN
LOCATION ON LOCATION_ID = WORKORDER_LOCATION_ID
GROUP BY
LOCATION_ID) T2 ON L.LOCATION_ID = T2.CONTACTLOCATION_LOCATION_ID`
Perhaps you could try using UNION to get a single sql result, then wrap it and give it an alias, and then apply a MAX on the field you wish, which both queries return. Keep in mind that to use UNION both queries must return the same set of field names.
Ex:
Query A:
Select a, b, c from T1 where....
Query B:
Select a, f, e from T2 where...
you would have:
SELECT MAX(e)
FROM
(
(Select a, b, c, NULL as f, NULL as e from T1 where....)
UNION
(Select a, NULL as b, NULL as c, f, e from T2 where...)
) t
If you need to use a join you can use a case statement to fetch the larger date.
SELECT
L.LOCATION_ID,
(CASE WHEN(T2.MaxDate IS NULL OR T1.MaxDate > T2.MaxDate)
THEN T1.MaxDate
ELSE T2.MaxDate
END) MaxDate
...
Try:
SELECT
L.LOCATION_ID, Max(MaxDate)
FROM
(
(
SELECT
LOCATION_ID, Max(LeadNote.NoteDate) AS MaxDate
FROM
LeadNote
JOIN
LOCATION
ON
LeadNote.LOCATION_ID = LOCATION.LOCATION_ID
GROUP BY
LOCATION_ID
)
UNION
(
SELECT
LOCATION_ID, Max(WORKORDER.WORKORDER_DATECREATED) AS MaxDate
FROM
WORKORDER
JOIN
LOCATION ON LOCATION_ID = WORKORDER_LOCATION_ID
GROUP BY
LOCATION_ID
)
)
It may need a little tweaking...but kudos to the comment by #DrCopyPaste if this works :)
You can do this with a simple join and a case statement:
SELECT
L.LOCATION_ID,
CASE WHEN(Max(LeadNote.NoteDate) IS NULL OR Max(LeadNote.NoteDate) > Max(WORKORDER.WORKORDER_DATECREATED)
THEN Max(LeadNote.NoteDate)
ELSE Max(WORKORDER.WORKORDER_DATECREATED) end AS maxDate
FROM
LOCATION AS L
LEFT JOIN LeadNote ON LeadNote.LOCATION_ID = LOCATION.LOCATION_ID
LEFT JOIN WORKORDER ON L.LOCATION_ID = WORKORDER_LOCATION_ID
GROUP BY L.LOCATION_ID