Adding an extra condition to SQL query - mysql

I'm trying to add an extra layer to my SQL query which looks like this:
SELECT
COUNT(*) totalCount
FROM
ts_room
WHERE
NOT EXISTS (
SELECT 1
FROM ts_roompref
JOIN ts_request
ON ts_roompref.request_id = ts_request.id
AND day_id = 1
AND period_id = 1
WHERE
ts_room.id = ts_roompref.room_id)
What I would like it to do is check that a row for the matching request.id does not exist in a table called ts_allocation. This is what I've attempted so far but it doesn't seem to be working:
SELECT
COUNT(*) totalCount
FROM
ts_room
WHERE
NOT EXISTS (
SELECT 1
FROM ts_roompref
JOIN ts_request
ON ts_roompref.request_id = ts_request.id
AND day_id = 1
AND period_id = 1
WHERE
ts_room.id = ts_roompref.room_id)
AND NOT EXISTS (
SELECT 1
FROM ts_roompref
JOIN ts_allocation
ON ts_roompref.request_id = ts_allocation.request_id
AND ts_allocation.status = "Allocated"
WHERE
ts_room.id = ts_roompref.room_id)
)
Any ideas? I've included my SQL Fiddle here: http://sqlfiddle.com/#!2/4540d/2

I think the problem has to do with the use of aliases: once I added alias names to the tables of your query, the query ran and returned some values (link to your modified sqlfiddle):
SELECT COUNT(*) totalCount
FROM ts_room rm
WHERE
NOT EXISTS (
SELECT 1
FROM ts_roompref rp
JOIN ts_request rq ON rp.request_id = rq.id AND day_id = 1 AND period_id = 1
WHERE rm.id = rp.room_id)
AND NOT EXISTS (
SELECT 1
FROM ts_roompref rp
JOIN ts_allocation a ON rp.request_id = a.request_id AND a.status = "Allocated"
WHERE rm.id = rp.room_id)

Related

(My)SQL JOIN - get teams with exactly specified members

Assume tables
team: id, title
team_user: id_team, id_user
I'd like to select teams with just and only specified members. In this example I want team(s) where the only users are those with id 1 and 5, noone else. I came up with this SQL, but it seems to be a little overkill for such simple task.
SELECT team.*, COUNT(`team_user`.id_user) AS cnt
FROM `team`
JOIN `team_user` user0 ON `user0`.id_team = `team`.id AND `user0`.id_user = 1
JOIN `team_user` user1 ON `user1`.id_team = `team`.id AND `user1`.id_user = 5
JOIN `team_user` ON `team_user`.id_team = `team`.id
GROUP BY `team`.id
HAVING cnt = 2
EDIT: Thank you all for your help. If you want to actually try your ideas, you can use example database structure and data found here: http://down.lipe.cz/team_members.sql
How about
SELECT *
FROM team t
JOIN team_user tu ON (tu.id_team = t.id)
GROUP BY t.id
HAVING (SUM(tu.id_user IN (1,5)) = 2) AND (SUM(tu.id_user NOT IN (1,5)) = 0)
I'm assuming a unique index on team_user(id_team, id_user).
You can use
SELECT
DISTINCT id,
COUNT(tu.id_user) as cnt
FROM
team t
JOIN team_user tu ON ( tu.id_team = t.id )
GROUP BY
t.id
HAVING
count(tu.user_id) = count( CASE WHEN tu.user_id = 1 or tu.user_id = 5 THEN 1 ELSE 0 END )
AND cnt = 2
Not sure why you'd need the cnt = 2 condition, the query would get only those teams where all of users having the ID of either 1 or 5
Try This
SELECT team.*, COUNT(`team_user`.id_user) AS cnt FROM `team`
JOIN `team_user` ON `team_user`.id_team = `team`.id
where `team_user`.id_user IN (1,5)
GROUP BY `team`.id
HAVING cnt = 2

Can you Divide 2 completely different query results into 1 result

I'm trying to divide the numeric results from 2 pretty different queries.
The end result should be Query 1 DIVIDED BY Query 2
Query 1 =
SELECT COUNT(DISTINCT(table1.ID)) AS count_1
FROM table1
INNER JOIN op
INNER JOIN Org
ON table1.EID = op.id
AND Op.OrgID = Org.ID
WHERE table1.TitleID = 123
AND op.BrandID = 1
AND op.Start <= NOW() AND op.End >= NOW();
Query 2 =
SELECT COUNT(DISTINCT user.id) AS count_2
FROM table1 INNER JOIN user INNER JOIN ur
ON table1.EID = user.id AND ur.userID = user.id
WHERE
user.BrandID = 1
AND table1.TitleID = 123
AND ur.role = 0
AND user.Inactive = 0;
Sure! You can use subselects to achieve this, though it will be pretty verbose!
SELECT
(
SELECT COUNT(DISTINCT(table1.ID)) AS count_1
FROM table1
INNER JOIN op
INNER JOIN Org
ON table1.EID = op.id
AND Op.OrgID = Org.ID
WHERE table1.TitleID = 123
AND op.BrandID = 1
AND op.Start <= NOW() AND op.End >= NOW()
) / (
SELECT COUNT(DISTINCT user.id) AS count_2
FROM table1 INNER JOIN user INNER JOIN ur
ON table1.EID = user.id AND ur.userID = user.id
WHERE
user.BrandID = 1
AND table1.TitleID = 123
AND ur.role = 0
AND user.Inactive = 0
);
Format however it feels the least ugly to you.
Use sub queries like this:
SELECT Q1.count_1 / Q2.Count_2
FROM
( ... Query1 ...) AS Q1
JOIN
( ... Query2 ...) AS Q2
ON 1=1
Replace Query1 and Query2 as your code.
Like this:
SELECT count_1 / count_2
FROM (SELECT COUNT(*) count_1 FROM foo) f
JOIN (SELECT COUNT(*) count_2 FROM bar) b ON 1=1;
http://sqlfiddle.com/#!2/c215e/1

using joins together with aggregates, and retrieving rows when no aggregate exists

The following query on my MySQL tables returns rows from the purchaseorder table that have corresponding entries in the deliveryorder table. How do I construct this query so that I get rows from the purchaseorder table even if no corresponding rows exist in the deliveryorder table? If the users want to see sql table CREATE statements, I can post those, but I'm not posting now as it really makes the question too big.
SELECT
`purchaseorder`.`id` AS `po_id`,
`purchaseorder`.`order_quantity` AS `po_order_quantity`,
`purchaseorder`.`applicable_approved_unit_rate` AS `po_unit_rate`,
`purchaseorder`.`applicable_sales_tax_rate` AS `po_tax_rate`,
`purchaseorder`.`order_date` AS `po_order_date`,
`purchaseorder`.`remarks` AS `po_remarks`,
`purchaseorder`.`is_open` AS `po_is_open`,
`purchaseorder`.`is_active` AS `po_is_active`,
`purchaseorder`.`approved_rate_id` AS `po_app_rate_id`,
`supplier`.`name` AS `sup_name`,
SUM(`deliveryorder`.`quantity`) AS `total_ordered`
FROM `purchaseorder`
LEFT JOIN `deliveryorder` ON (`deliveryorder`.`purchase_order_id` = `purchaseorder`.`id`)
INNER JOIN `approvedrate` ON (`purchaseorder`.`approved_rate_id` = `approvedrate`.`id`)
INNER JOIN `supplier` ON (`approvedrate`.`supplier_id` = `supplier`.`id`)
WHERE (
`purchaseorder`.`is_active` = 1
AND `purchaseorder`.`is_open` = 1
AND `deliveryorder`.`is_active` = 1
AND `approvedrate`.`material_id` = 2
)
HAVING `purchaseorder`.`order_quantity` >= `total_ordered` + 1
You have an aggregating function but no GROUP BY clause, which is wierd, but anyway - something like this? Oops - edited...
SELECT po.id po_id
, po.order_quantity po_order_quantity
, po.applicable_approved_unit_rate po_unit_rate
, po.applicable_sales_tax_rate po_tax_rate
, po.order_date po_order_date
, po.remarks po_remarks
, po.is_open po_is_open
, po.is_active po_is_active
, po.approved_rate_id po_app_rate_id
, s.name sup_name
, SUM(do.quantity) total_ordered
FROM purchaseorder po
LEFT
JOIN deliveryorder do
ON do.purchase_order_id = po.
AND do.is_active = 1
LEFT
JOIN approvedrate ar
ON ar.id = po.approved_rate_id
AND ar.material_id = 2
LEFT
JOIN supplier s
ON s.id = ar.supplier_id
WHERE po.is_active = 1
AND po.is_open = 1
HAVING po.order_quantity >= total_ordered + 1
I couldn't work out how to get the desired results all in one query, but ended up using the following two queries to fulfill my requirements: -
1st query
SELECT
pot.`id` AS `po_id`,
pot.`order_quantity` AS `po_order_quantity`,
pot.`applicable_approved_unit_rate` AS `po_unit_rate`,
pot.`applicable_sales_tax_rate` AS `po_tax_rate`,
pot.`is_open` AS `po_is_open`,
pot.`is_active` AS `po_is_active`,
st.`id` AS `sup_id`,
st.`name` AS `sup_name`,
SUM(dot.`quantity`) AS `total_ordered`
FROM `purchaseorder` pot
INNER JOIN `deliveryorder` dot ON (dot.`purchase_order_id` = pot.`id`)
INNER JOIN `approvedrate` art ON (pot.`approved_rate_id` = art.`id`)
INNER JOIN `supplier` st ON (art.`supplier_id` = st.`id`)
WHERE (
pot.`is_active` = 1
AND pot.`is_open` = 1
AND art.`material_id` = #materialid
AND art.`in_effect` = 1
AND art.`is_active` = 1
AND dot.`is_active` = 1
AND st.`is_active` = 1
)
HAVING pot.`order_quantity` >= `total_ordered` + #materialquantity
2nd query
SELECT
pot.`id` AS `po_id`,
pot.`order_quantity` AS `po_order_quantity`,
pot.`applicable_approved_unit_rate` AS `po_unit_rate`,
pot.`applicable_sales_tax_rate` AS `po_tax_rate`,
pot.`is_open` AS `po_is_open`,
pot.`is_active` AS `po_is_active`,
st.`id` AS `sup_id`,
st.`name` AS `sup_name`,
0 AS `total_ordered`
FROM `purchaseorder` pot
INNER JOIN `approvedrate` art ON (pot.`approved_rate_id` = art.`id`)
INNER JOIN `supplier` st ON (art.`supplier_id` = st.`id`)
WHERE (
pot.`is_active` = 1
AND pot.`is_open` = 1
AND art.`material_id` = #materialid
AND art.`in_effect` = 1
AND art.`is_active` = 1
AND st.`is_active` = 1
AND pot.`order_quantity` >= #materialquantity
AND pot.`id` NOT IN
(
SELECT dot.`purchase_order_id`
FROM `deliveryorder` dot
WHERE dot.is_active = 1
)
)

SQL query not returning anything

How do I link across and get the variables of three tables, I want to get the linked facilities for each room but currently my record seems to be returning nothing.
I would like to return a new column header for facilities as well: http://sqlfiddle.com/#!2/8d6ca/25
The fiddle can be found here
SELECT *
FROM ts_room rm
WHERE
NOT EXISTS (
SELECT 1
FROM ts_roompref rp
JOIN ts_request rq ON rp.request_id = rq.id AND day_id = 1 AND period_id = 1
WHERE rm.id = rp.room_id)
AND NOT EXISTS (
SELECT 1
FROM ts_roompref rp
JOIN ts_allocation a ON rp.request_id = a.request_id AND a.status = "Allocated"
WHERE rm.id = rp.room_id)
AND EXISTS (
SELECT 1
FROM ts_roomfacilities f
JOIN ts_room b ON f.room_id = b.id
WHERE rm.id = f.room_id AND
f.facilities_id=2);
AND EXISTS (
SELECT 1
FROM ts_facilities f1
JOIN ts_roomfacilities c ON f2.id = c.id
WHERE rm.id = f.room_id);
There's a ; in the middle of your query which you should remove

sql server cross join

I have the following query:
select
tt.ItemOrder, tt.DisplayVal as Task, tt.Responsible as ResParty,
tt.DaysDue,
ActualDate = (select convert(varchar(10), cnfmdate, 101) from ProSer where PId = #PID), PDate = #PDate
from
tblTimeline tt
where
tt.ID = 1
What I need to do is to put it in a view such that I can call the view simply using the PID.
I came up with the following and used the cross join:
create view view1 as
select
ps.PID, tt.ID, tt.ItemOrder, tt.DisplayVal as Task,
tt.Responsible as ResParty, tt.DaysDue,
ps.cnfmdate As ActualDate, ProgStartDate as ProgramDate
from
tblTimeline tt
cross join
ProSer ps
where
tt.ID = 1 and ps.cancelled = 0
Notice now, I can do the following
select *
from view1
where PID = '34343'
and then I can retrieve it from the view.
Now, I am not sure how to do similiarly with the following in which case I need to put it in a cross join similarly to how I did above.
Notice how actual date is somehat more involved. I need to use the cross table similarly to how I did it above but not as you can see, it is somewhat more involved.
(notice for this part, I will simly join to the view1 that I have above with UNION
select
tt.ItemOrder, tt.DisplayVal as Task, tt.Responsible as ResParty,
ActualDate = (
CASE
WHEN
NOT EXISTS(SELECT * FROM Spls WHERE RequestRcvd = 1 AND PID = #PID)
THEN
'N/A'
WHEN EXISTS (SELECT * FROM spls WHERE RequestRcvd = 1 AND RequestRcvdDate IS NOT NULL)
THEN
(SELECT CONVERT(VARCHAR(10),MAX(RequestRcvdDate),101) from spls WHERE RequestRcvd = 1 AND PID = #PID)
END
)
from
tblTimeline tt
where
tt.ID = 9
I need to know how I can create this in a cross join (which will be inside of a view) such that I can do the following similarly to how I did the above one
select *
from view1
where PID = '34343'
and then I can retrieve it from the view.
There might be a way to simplify the query, but the following should work:
select p.pid, tt.ItemOrder, tt.DisplayVal as Task,
tt.Responsible as ResParty,
ActualDate = (CASE WHEN NOT EXISTS(SELECT * FROM Spls WHERE RequestRcvd = 1 AND spls.PID = p.PID)
THEN 'N/A'
WHEN EXISTS (SELECT * FROM spls WHERE RequestRcvd = 1 AND RequestRcvdDate IS NOT NULL)
THEN (SELECT CONVERT(VARCHAR(10),MAX(RequestRcvdDate),101) from spls WHERE RequestRcvd = 1 AND spls.PID = p.PID)
END)
from tblTimeline tt cross join
poser p
where tt.ID = 9
All I did was add the cross join to poser and replace #PID with p.pid. The results is a subquery that contains a reference to a table at an outer level. Such a subquery is called a correlated subquery.