INNER JOIN inside Subquery SQL - 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

Related

Counting number of rows resulting from a nested SQL select statement with a JOIN

I have the following SQL statement.
SELECT COUNT(a.id), a.project_id, p.is_recommended
FROM assessments a
INNER JOIN projects p ON p.id=a.project_id
WHERE p.is_recommended = 1
GROUP BY project_id
HAVING COUNT(a.id) >= 3
I would like to count the resulting number of rows.
If not for the INNER JOIN, all I'd have to do is something like this...
SELECT * FROM
(SELECT COUNT(id), project_id
FROM assessments
GROUP BY project_id
HAVING COUNT(id) >= 3) assessments
But how do I calculate the resulting number of rows if my statement has a JOIN? What syntax should I be using?
SELECT COUNT(*)
FROM (SELECT COUNT(a.id), a.project_id, p.is_recommended
FROM assessments a
INNER JOIN projects p ON p.id=a.project_id
WHERE p.is_recommended = 1
GROUP BY project_id
HAVING COUNT(a.id) >= 3
) AS counts

Inner join without column and without using pivot?

In the following query, I have three cte that will always display one row each.
Is there a simple way where I can display each value horizontally without having to group by weeknum for the inner join?
I also prefer not using the pivot operator or anything else that makes a simple query unnecessarily complex.
;with cteSales as
(
select count(*) as 'Total' from sales where weeknum = 33
),
cteVendors as
(
select count(*) as 'vendors' from Vendors where weeknum = 33
),
cteClients as
(
select count(*) as 'clients' from Clients where weeknum = 33
)
select total, vendors, clients from
cteSales inner join cteVendors on ??
inner join cteClients on ??
You could just use 3 subqueries:
SELECT (SELECT COUNT(*) FROM dbo.sales WHERE weeknum = 33) AS Total,
(SELECT COUNT(*) FROM dbo.Vendors WHERE weeknum = 33) AS Vendors,
(SELECT COUNT(*) FROM dbo.Clients WHERE weeknum = 33) AS Clients;
If you have to use CTEs, use a CROSS JOIN:
--; is a statement TERMINATOR, it goes at the end of ALL your statements,
-- not statement that require the previous statement to be properly terminated.
WITH cteSales AS
(SELECT COUNT(*) AS Total
FROM sales
WHERE weeknum = 33),
cteVendors AS
(SELECT COUNT(*) AS vendors
FROM Vendors
WHERE weeknum = 33),
cteClients AS
(SELECT COUNT(*) AS clients
FROM Clients
WHERE weeknum = 33)
SELECT S.Total,
V.vendors,
C.clients
FROM cteSales S
CROSS JOIN cteVendors V
CROSS JOIN cteClients C;

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

How to get 0 in COUNT from different months and status?

I have two tables item and status.
item is a table like this:
id date status_id
1 10-02-2013 1
2 11-02-2013 1
3 11-03-2013 2
... ... ...
status is a table like this:
id status_name
1 first
2 second
3 three
... ...
I'd like as a result something like this:
month status total
2 first 2
2 second 0
2 three 0
3 first 0
3 second 1
3 three 0
I am using SQLite through web2py:
select
month, status.status_name, ifnull(total, 0)
from
status
left join
(select
status.id,
strftime('%m', date) as month,
status_name as status,
count(status_name) as total
from
status
inner join
item
on status.id = item.status_id
group by nombre, web2py_extract('month', date)
) sub
on sub.id = status.id
I am using the function web2py_extract to group date by month.
My result is the next:
month status total
2 first 2
3 second 1
However, I am not getting the rows with empty value. What I am doing wrong?
You can do this with a cross join and then left outer join:
select m.month, s.status, coalesce(i.cnt, 0) as cnt
from (select distinct strftime('%m', date) as month from item) m cross join
(select id, status from status) s left outer join
(select strftime('%m', date) as month, status_id, count(*) as cnt
from item i
group by strftime('%m', date), status_id
) i
on i.month = m.month and i.status_id = s.id;
The cross join creates all combinations of month and status. The left join brings in the count. The coalesce() converts NULL to 0 when there is no match.
The table with the non-matching values you want anyway must be on the left side of the LEFT JOIN.
This means you need item LEFT JOIN status in the inner query.
(The outer query does not need an outer join.)
SELECT MONTH(date) as Month, Status.status_name, COUNT(*) as Total
FROM Item
LEFT JOIN Status on Item.status_id = Status.id

Stuck on what is a simple query

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