I have two tables.
diseases
-----------------------------
| ID | NAME |
-----------------------------
| 1 | Disease 1 |
| 2 | Disease 2 |
| 3 | Disease 3 |
diseases_symptoms
-----------------------------
| DISEASE_ID | SYMPTOM_ID |
-----------------------------
| 1 | 1 |
| 1 | 2 |
| 1 | 3 |
| 1 | 4 |
| 2 | 1 |
| 2 | 2 |
I want to select all diseses which have symptoms 1 or 2 and 3 or 4.
I've tried:
SELECT *
FROM diseases_symtoms
WHERE (symptoms = '1' OR symptoms = '2')
AND (symptoms = '3' OR symptoms = '4')
And:
SELECT *
FROM diseases_symtoms
WHERE symptoms IN ('1','2')
AND symptoms IN ('3','4')
...but it is not working.
Keep in mind that SELECT can only examine one row at a time. Both those queries act as if you can detect a 1 and a 3 simultaneously (for example), which is not possible.
To consider multiple rows at once, you can either join to two separate copies of the table, or try a grouping like this:
SELECT diseases.*
FROM diseases
INNER JOIN diseases_symptoms ON (disases_symptoms.disease_id = diseases.disease_id)
GROUP BY diseases.disease_id
HAVING SUM(IF(symptoms = 1 OR symptoms = 2, 1, 0) > 0 AND SUM(IF(symptoms = 3 OR symptoms = 4, 1, 0) > 0
You could try...
SELECT DISTINCT *
FROM diseases
WHERE EXISTS (SELECT *
FROM disease_symptoms
WHERE disease.disease_id = disease_symptoms.disease_id AND
symptom_id IN (1,2)) AND
EXISTS (SELECT *
FROM disease_symptoms
WHERE disease.disease_id = disease_symptoms.disease_id AND
symptom_id IN (3,4));
SELECT d.* FROM diseases AS d
INNER JOIN disease_symptoms AS s1 ON s1.DISEASE_ID = d.ID WHERE SYMPTOM_ID IN (1, 2)
INNER JOIN disease_symptoms AS s2 ON s2.DISEASE_ID = d.ID WHERE SYMPTOM_ID IN (3, 4)
GROUP BY d.ID
Related
I have a table tblPhotos of photo details:
| photoID | photoName |
| ------- | --------- |
| 1 | w |
| 2 | x |
| 3 | y |
| 4 | z |
and another table tblPhotoTags of tags to photos:
| photoID | tagID |
| ------- | ----- |
| 1 | 1 |
| 1 | 2 |
| 2 | 1 |
| 3 | 2 |
| 4 | 1 |
| 4 | 2 |
I am trying make a couple of queries that will pick out the photos that have any given tags, either AND or OR. In the example let's say I am searching for the photos linked to tagID 1 AND/OR 2.
OR should pick out all of the photos (1, 2, 3 and 4).
AND should only pick out 1 and 4.
I have the following for OR which works fine:
SELECT DISTINCT tblPhotos.photoID FROM tblPhotos
INNER JOIN tblPhotoTags ON tblPhotos.photoID = tblPhotoTags.photoID
WHERE tblPhotoTags.tagID = 1 OR tblPhotoTags.tagID = 2
But I am struggling to work out how to do the AND query.
If you need only the ids of the photos, then there is no need to join to tblPhotos.
For the 1st case (OR), use DISTINCT and just a WHERE clause:
SELECT DISTINCT photoID
FROM tblPhotoTags
WHERE tagID IN (1, 2);
For the 2nd case (AND) use aggregation and set the condition in the HAVING clause:
SELECT photoID
FROM tblPhotoTags
WHERE tagID IN (1, 2)
GROUP BY photoID
HAVING COUNT(*) = 2 -- the number of tagIDs in the IN list
If you also want the name of the photos then join to tblPhotos:
SELECT DISTINCT p.*
FROM tblPhotos p INNER JOIN tblPhotoTags t
ON t.photoID = p.photoID
WHERE t.tagID IN (1, 2);
and:
SELECT p.photoID, p.photoName
FROM tblPhotos p INNER JOIN tblPhotoTags t
ON t.photoID = p.photoID
WHERE t.tagID IN (1, 2)
GROUP BY p.photoID, p.photoName
HAVING COUNT(*) = 2 -- the number of tagIDs in the IN list
See the demo.
I have a table records of store id, processing batch id and start time as follows:
|store_id | batch_id | process_start_time |
| A | 1 | 10 |
| B | 1 | 40 |
| C | 1 | 30 |
| A | 2 | 400 |
| B | 2 | 800 |
| C | 2 | 600 |
| A | 3 | 10 |
| B | 3 | 80 |
| C | 3 | 90 |
Here, rows needed to be grouped by batch_id and time_taken is difference of process_start_time of store A and store C.
So, the expected result would be:
batch_id | time_taken
1 | 20
2 | 200
3 | 80
I tried to do something like:
select batch_id, ((select process_start_time from records where store_id = 'C') - (select process_start_time from records where store_id = 'A')) as time_taken
from records group by batch_id;
But couldn't figure out to select specific rows in that particular group.
Thank you for looking into!
Update: the process_start_time column not necessarily max for store C
You seem to want conditional aggregation and arithmetic:
select batch_id,
(max(case when store_id = 'C' then process_start_time end) -
min(case when store_id = 'A' then process_start_time end)
) as diff
from records
group by batch_id;
You can try a self join.
SELECT r1.batch_id,
r1.process_start_time - r2.process_start_time time_taken
FROM records r1
INNER JOIN records r2
ON r1.batch_id = r2.batch_id
WHERE r1.store_id = 'C'
AND r2.store_id = 'A';
Here's another answer. This is using two instances of the records table and we link them up with where clauses and exists as follows:
select a.batch_id,
c.process_start_time - a.process_start_time as time_taken
from records a,
records c
where a.store_id = 'A'
and c.store_id = 'C'
and exists (
select 1
from records x
where x.batch_id = a.batch_id
and x.batch_id = c.batch_id
);
SELECT DISTINCT
store_a.batch_id,
store_c.process_start_time - store_a.process_start_time AS 'time_taken'
FROM records store_a
INNER JOIN records store_c
ON store_a.batch_id = store_c.batch_id
AND store_c.store_id = 'C'
AND store_a.store_id = 'A'
I have a table Follow, which only holds records of which UserID follows which TargetID.
If asked for user A:
If neither A or B are following eachother, they have status of 0 for unrelated, and aren't included in the results.
If user A is following B but not vice versa, B has status 1 for
being followed.
If user B is following A but not vice versa, B has
status 2 for being a follower.
If A is following B, and B following
A, B has status of 3 for being a friend.
How can I, in a single MySQL query, get the relationship status for a given user and all its relationships above status 0?
Example:
Users:
+----+-------+
| id | Name |
+----+-------+
| 1 | Bob |
| 2 | Steve |
| 3 | Scott |
| 4 | Mary |
+----+-------+
Follow:
+----+--------+----------+
| id | UserID | TargetID |
+----+--------+----------+
| 1 | 1 | 2 |
| 2 | 1 | 3 |
| 3 | 2 | 1 |
| 4 | 4 | 1 |
+----+--------+----------+
Expected result for user 1:
+----------+--------+-------+
| TargetID | Status | Name |
+----------+--------+-------+
| 2 | 3 | Steve | (friend)
| 3 | 1 | Scott | (following)
| 4 | 2 | Mary | (follower)
+----------+--------+-------+
You can use subqueries as illustrated below:
-- FOR USER 1
SELECT A.id TargetID,
SUM(IFNULL((SELECT 1 C FROM Follow B WHERE B.UserID=1 AND B.TargetID=A.id),0) +
IFNULL((SELECT 2 C FROM Follow D WHERE A.id=D.UserID AND D.TargetID=1), 0)) Status
, A.name
FROM (SELECT * FROM Users WHERE ID<>1) A
GROUP BY A.id, A.Name
HAVING Status>0; -- for a compact result
-- NOW GLOBALLY
SELECT A.UserID, A.id TargetID,
SUM(IFNULL((SELECT 1 C FROM Follow B WHERE B.UserID=A.UserID AND B.TargetID=A.id),0) +
IFNULL((SELECT 2 C FROM Follow D WHERE A.id=D.UserID AND D.TargetID=A.UserID), 0)) Status
, A.name
FROM (SELECT E.id UserID, F.* FROM Users E JOIN Users F ON E.id<>F.id) A
GROUP BY A.UserID, A.id, A.Name
HAVING Status>0 -- for a compact result
ORDER BY A.UserID;
See DEMO on SQL Fiddle
I have not tried this but try something among the lines of:
Select t.targetid as TargetId,
IF (
(select count(id) from follow where
follow.Userid = f.target.id and follow.target_id = u.id) > 1,
-- mean’s the target is following user 1
(IF (
(select count(id) from follow where
follow.Userid = u.id and follow.target_id = f.targetid) > 1, 3, 2))
-- if user1 is following aswell, then its a friend, else its a follower
, 1)
-- else means its a following
as status,
u.name as Name from follow f
inner Join users u on u.id = f.targetid
where u.id = 1
Inner join to select user 1's relations (if it doesn't exist, they aren't related)
If there is a record, means they are one of 3:
I have following tables:
A:
+----+-----------+-------+----------+
| ID | PaymentID | Price | Quantity |
+----+-----------+-------+----------+
| 1 | 1 | 128 | 1 |
| 2 | 2 | 10 | 2 |
| 3 | 2 | 11 | 1 |
| 4 | 3 | 100 | 2 |
+----+-----------+-------+----------+
B:
+-----------+------------+
| PaymentID | TotalPrice |
+-----------+------------+
| 1 | 128 |
| 2 | 31 |
| 3 | 201 |
+-----------+------------+
And query:
SELECT a.ID
FROM a
LEFT JOIN b ON b.PaymentID = a.PaymentID
WHERE b.TotalPrice = (a.Price * a.Quantity)
It works fine when a.PaymentID is unique, but some transactions in table A are separated and paid (table B) together. Query above return a.ID = 1 but I need to return a.ID = 1,2,3.
a.PaymentID(1): 128 * 1 = 128 MATCH
a.PaymentID(2): 10 * 2 + 11 * 1 = 31 MATCH
a.PaymentID(3): 100 * 2 = 200 NOT MATCH
SQL Fiddle
You are trying to join sum of Price and amount from table a to table b along with the PaymentId, and using it onto a joining clause which would be calculated per row based not on aggregate based.
You may need to first find the aggregate part and then join something as
select
a.ID
from a
left join (
select sum(Price*Quantity) as tot,PaymentID
from a group by PaymentID
)x on x.PaymentID = a.PaymentID
join b on b.PaymentID = a.PaymentID and x.tot = b.TotalPrice
http://www.sqlfiddle.com/#!9/3b261/45
Try this statement:
SELECT a.ID, b.totalprice
FROM a
LEFT JOIN b ON b.PaymentID = a.PaymentID
group by b.paymentID
having TotalPrice = sum(a.Price * a.Quantity)
SQLFIDDLE
UPDATE: After clarification:
select a.id from a where paymentId in(
select paymentID from(
SELECT a.paymentID as paymentID, b.totalprice
FROM a
LEFT JOIN b ON b.PaymentID = a.PaymentID
group by b.paymentID
having TotalPrice = sum(a.Price * a.Quantity)) as c )
I have slight problem with mysql query. I have two tables:
bioshops
+------------+-------------+
| bioshop_id | name |
+------------+-------------+
| 1 | Bioshop1 |
| 2 | Bioshop2 |
+------------+-------------+
bioshop_have_product
+----+-----------------+--------------+
| id | bioshop_id | product_id |
+----+-----------------+--------------+
| 1 | 1 | 1 |
| 2 | 1 | 2 |
| 3 | 2 | 1 |
| 4 | 2 | 3 |
+----+-----------------+--------------+
The tables are much more complex but this is the important structure. prodict_id in bioshop_have_product is also FK. I need to select bioshops witch contains all products that I ask. Example:
if I need bioshops with product 1 it should return Bioshop1 and Bioshop2 with all products
if I need bioshops with product 1 and 2 it should return Bioshop1 with all products
My query is:
SELECT bs.name AS name,
bs.id AS bioshop_id,
bshd.id AS id,
bshd.product_id AS product_id
FROM bioshops bs
JOIN bioshop_have_product bshp
ON bs.bioshop_id = bshp.bioshop_id
WHERE (bshp.bioshop_id = bs.bioshop_id AND bshp.product_id = '1')
AND (bshp.bioshop_id = bs.bioshop_id AND bshp.product_id = '2')
but this returns nothing and I want it to return Bioshop1 because only Bioshop1 countains both objects.
You can try something like this:
SELECT bs.name AS name,
bs.id AS bioshop_id,
bshp.id AS id,
bshp.product_id AS product_id
FROM bioshop bs
JOIN bioshop_have_product bshp
ON bs.id = bshp.bioshop_id AND
(SELECT COUNT(*) FROM bioshop_have_product WHERE product_id IN (1, 2) AND bs.id = bioshop_id) = X
where X should be equal to the count of different products you whant to check, for instance 2 in your second case.
SELECT bioshop_id
FROM bioshop_have_product
WHERE product_id IN (1,2)
GROUP
BY bioshop_id
HAVING COUNT(*) = 2;