I have three tables. Config, capability, and config_capability which associates the first two.
A config can have more than one capability so config_capability could look like
id | config_id | capability_id
1 1 1
2 1 2
3 2 1
4 2 2
5 2 3
I want to find the configs that have only certain capabilities.
SELECT
config.name
FROM
config
JOIN
config_capability AS cc
ON
config.id = cc.config_id
JOIN
capability
ON
cc.capability_id = capability.id
WHERE
config.node_count <= 4
AND cc.capability_id IN (
SELECT id
FROM capability
WHERE capability.name = 'cap1'
OR capability.name = 'cap2')
GROUP BY config.name
HAVING COUNT(cc.config_id) = 2
This query gives me config 1 and config 2 but I only want to find configs with capabilities 1 and 2 not 3
You can rewrite your query as below no need to use extra subquery while you have that table in join
SELECT
c.name
FROM
config c
JOIN
config_capability AS cc
ON
c.id = cc.config_id
JOIN
capability ca
ON
cc.capability_id = ca.id
WHERE
config.node_count <= 4
GROUP BY c.name
HAVING sum(ca.name NOT IN('cap1','cap2')) = 0
Demo
You can try:
HAVING COUNT(cc.config_id) = 2 and max(cc.config_id)<3
Related
In sql help i have 3 tables, table one is asset table which is as follow
id
asset_code
asset_name
asset_group
asset_quantity
1
A001
computer
4
7
2
A002
keyboard
6
4
and another table is asset_allocation
id
asset_id
allocated_quantity
allocated_location
returned
1
1
2
IT office
no
2
2
1
main hall
yes
the last table is asset_liquidated which will present assets that are no longer going to be used
id
asset_id
liquidated_quantity
1
1
1
Now lets say that i have 7 computer out of which 2 are allocated but not returned and i have 4 keyboards out of which 1 is allocated and it is returned back and 1 computer is liquidated means it is never going to be used
so now here i want to join these 3 tables and find inventory of my current stock in hand.
Now this is the query now i need to add this
where asset_allocation.returned is enum no inside this query
SELECT id,asset_code, asset_name, asset_group, asset_quantity,allocated_quantity,liquidated_quantity,
asset_quantity - COALESCE(AA.allocated_quantity, 0) - COALESCE(AL.liquidated_quantity, 0) available_quantity
FROM asset A
LEFT JOIN (SELECT asset_id, SUM(allocated_quantity) allocated_quantity
FROM asset_allocation
GROUP BY asset_id) AA ON A.id = AA.asset_id
LEFT JOIN (SELECT asset_id, SUM(liquidated_quantity) liquidated_quantity
FROM asset_liquidated
GROUP BY asset_id) AL ON A.id = AL.asset_id;
I believe what you are looking for is adding WHERE returned = 'no' in your first JOIN like so:
SELECT id,asset_code, asset_name, asset_group, asset_quantity,allocated_quantity,liquidated_quantity,
asset_quantity - COALESCE(AA.allocated_quantity, 0) - COALESCE(AL.liquidated_quantity, 0) available_quantity
FROM asset A
LEFT JOIN (SELECT asset_id, SUM(allocated_quantity) allocated_quantity
FROM asset_allocation
WHERE returned = 'no'
GROUP BY asset_id) AA ON A.id = AA.asset_id
LEFT JOIN (SELECT asset_id, SUM(liquidated_quantity) liquidated_quantity
FROM asset_liquidated
GROUP BY asset_id) AL ON A.id = AL.asset_id;
That changes the available quantity for keyboard from 3 to 4 for me
your query:
vs. mine:
I have two tables as below.
PermissionAccessEntities
peID | petID
-------------------
1 | 1
2 | 4
3 | 1
4 | 2
5 | 4
6 | 4
-------------------
PermissionAccessEntityGroups
pegID | peID | gID
-----------------------------
1 | 5 | 1
2 | 5 | 2
3 | 5 | 3
4 | 6 | 2
5 | 6 | 3
-----------------------------
Now I've a getOne doctrine query as below-
select pae.peID from PermissionAccessEntities pae
left join PermissionAccessEntityGroups paeg1 on pae.peID = paeg1.peID
left join PermissionAccessEntityGroups paeg2 on pae.peID = paeg2.peID
where petID = 4 and paeg1.gID = 2 and paeg2.gID = 3;
Which returns 5 & 6. But I want to get the result which has exact number of matching rows. In this case which is 6.
Is there any way to use JOIN to fetch the same resultset as above ?.
Help is much appreciated.
Where condition will not help you in this case. Because, you want to consider count of all the rows for further filtering. You will need to use Group By with conditional filtering using Having clause.
We can also simplify query to use only one join with the PermissionAccessEntityGroups table.
Count() function is used to count the number of rows in a group. We can also use Sum( conditional statements ) to count number of rows matching a condition. Conditional statement will return 1 for matching rows, and 0 for non-matching rows.
Try the following query instead:
SELECT pae.peID
FROM PermissionAccessEntities AS pae
LEFT JOIN PermissionAccessEntityGroups AS paeg
ON pae.peID = paeg.peID
WHERE pae.petID = 4
GROUP BY pae.peID
HAVING COUNT(*) = SUM(paeg.gID IN (2,3))
DB Fiddle DEMO
Now, remember that Count(NULL) = 0; however COUNT(0) = COUNT(1) = 1. So, another way of writing this query using Count() function only is:
SELECT pae.peID
FROM PermissionAccessEntities AS pae
LEFT JOIN PermissionAccessEntityGroups AS paeg
ON pae.peID = paeg.peID
WHERE pae.petID = 4
GROUP BY pae.peID
HAVING COUNT(*) = COUNT(CASE WHEN paeg.gID IN (2,3) THEN 1 END)
DB Fiddle DEMO 2
You can achieve your desired result by first looking for entries which match (2,3) and then seeing if any of those also match one of the other values. Any which doesn't (paeg2.peID IS NULL) is an exact match:
SELECT DISTINCT(pae.peID)
FROM PermissionAccessEntities pae
JOIN PermissionAccessEntityGroups paeg1 ON paeg1.peID = pae.peID AND paeg1.gID IN (2,3)
LEFT JOIN PermissionAccessEntityGroups paeg2 ON paeg2.peID = pae.peID AND paeg2.gID NOT IN (2,3)
WHERE pae.petID = 4 AND paeg2.peID IS NULL
Demo on dbfiddle
SELECT pae.peID FROM PermissionAccessEntities pae
INNER JOIN PermissionAccessEntityGroups paeg1 ON pae.peID=paeg1.peID
WHERE pae.petID = 4 AND paeg1.peID NOT IN (SELECT DISTINCT peID FROM
PermissionAccessEntityGroups WHERE gID NOT IN (2,3));
I need to implement a function which returns all the networks the installation is not part of.
Following is my table and for example if my installation id is 1 and I need all the network ids where the installation is not part of then the result will be only [9].
network_id | installation_id
-------------------------------
1 | 1
3 | 1
2 | 1
2 | 2
9 | 2
2 | 3
I know this could be solved with a join query but I'm not sure how to implement it for the same table. This is what I've tried so far.
select * from network_installations where installation_id = 1;
network_id | installation_id
-------------------------------
1 | 1
2 | 1
3 | 1
select * from network_installations where installation_id != 1;
network_id | installation_id
-------------------------------
9 | 2
2 | 2
2 | 3
The intersection of the two tables will result the expected answer, i.e. [9]. But though we have union, intersect is not present in mysql. A solution to find the intersection of the above two queries or a tip to implement it with a single query using join will be much appreciated.
The best way to do this is to use a network table (which I presume exists):
select n.*
from network n
where not exists (select 1
from network_installation ni
where ni.network_id = n.network_id and
ni.installation_id = 1
);
If, somehow, you don't have a network table, you can replace the from clause with:
from (select distinct network_id from network_installation) n
EDIT:
You can do this in a single query with no subqueries, but a join is superfluous. Just use group by:
select ni.network_id
from network_installation ni
group by ni.network_id
having sum(ni.installation_id = 1) = 0;
The having clause counts the number of matches for the given installation for each network id. The = 0 is saying that there are none.
Another solution using OUTER JOIN:
SELECT t1.network_id, t1.installation_id, t2.network_id, t2.installation_id
FROM tab t1 LEFT JOIN tab t2
ON t1.network_id = t2.network_id AND t2.installation_id = 1
WHERE t2.network_id IS NULL
You can check at http://www.sqlfiddle.com/#!9/4798d/2
select *
from network_installations
where network_id in
(select network_id
from network_installations
where installation_id = 1
group by network_id )
I have 3 tables like this
soft_id soft_name
1 Office
pu_id soft_id pu_quantity
1 1 10
2 1 20
3 1 30
own_id soft_id owner
1 1 Peter
2 1 Tommy
3 1 David
How can I have a result like this in one single mysql query
soft_id soft_name sum(pu_quantity) count(owner)
1 Office 60 3
Try this:
SELECT a.soft_id,
a.soft_name,
b.p_cnt AS quantity,
c.o_cnt AS owner_count
FROM soft a
INNER JOIN
(SELECT soft_id, SUM(pu_quantity) AS p_cnt FROM product GROUP BY soft_id
) b
ON a.soft_id = b.soft_id
INNER JOIN
(SELECT soft_id, COUNT(*) AS o_cnt FROM owner GROUP BY soft_id
) c
ON b.soft_id = c.soft_id
GROUP BY a.soft_id,
a.soft_name
SQLFiddle
Note: assuming that the table names are soft, product and owner respectively.
Try this
SELECT S.soft_id,S.soft_name,P.sum(pu_quantity),O.count(owner)
FROM Soft S INNER JOIN Product P ON S.soft_id = P.soft_id
Inner JOIN Owner O = P.soft_id = O.soft_id
Group By S.soft_id,P.soft_id,O.soft_id,S.soft_name
I am making a MySQL query where I want to retrieve an ID but only if I find a match for it in all the rows which I specify in the query.
Table: view_layout_rows
ID owner rows
___________________
49 1 2
50 1 2
Table: view_layout_rows_columns
ID row columns
___________________
49 1 5
49 2 4
50 1 5
50 2 5
SELECT vlr.id
FROM view_layout_rows vlr
INNER JOIN view_layout_rows_columns vlrc
ON vlr.id = vlrc.id
WHERE vlr.rows = 2
AND (vlr.owner = 0 OR vlr.owner = 1)
AND all of the following conditions should be satisfied:
(vlrc.row = 1 AND vlrc.columns = 5)
(vlrc.row = 2 AND vlrc.columns = 5)
Only ID 50 should be returned. 49 should NOT be returned as it only satisfies the first of the final two clauses.
How might I go about this?
(Please note, I asked this question previously but my requirement was unclear. Second attempt.)
Thanks in advance for any suggestions.
Double join to the rescue! :-)
SELECT vlc.*
FROM view_layout_rows vlc
INNER JOIN view_layout_rows_columns vlrc1 ON vlrc1.id = vlc.id
INNER JOIN view_layout_rows_columns vlrc2 ON vlrc2.id = vlc.id
WHERE vlrc1.row = 1 AND vlrc1.columns = 5
AND vlrc2.row = 2 AND vlrc2.columns = 5
/* imported from original query */
AND vlr.rows = 2
AND (vlr.owner = 0 OR vlr.owner = 1);
Single access of each table:
select r.*
from view_layout_rows r
join (select id, count(*) rec_count
from view_layout_rows_columns
where row in (1,2) and
columns = 5
group by id
having count(*) = 2) c
on r.id = c.id
where r.rows = 2 and
r.owner in (0,1)