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
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
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
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
)
)
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
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.