I have this data in a table called PROD
| Project | Position | Status |
|---------|----------|--------|
| 1 | 1 | A |
| 1 | 2 | A |
| 2 | 1 | A |
| 2 | 2 | B |
| 3 | 1 | B |
| 3 | 2 | B |
| 4 | 1 | A |
| 4 | 2 | A |
I'm trying to get all the Projects that has at least one Position with Status = B.
| Project | Position | Status |
|---------|----------|--------|
| 2 | 1 | A |
| 2 | 2 | B |
| 3 | 1 | B |
| 3 | 2 | B |
I've tried using a JOIN like this:
SELECT * FROM PROD A JOIN PROD B ON A.PROD-Project = B.PROD-Project WHERE B.PROD-Status = 'B'
This give me an empty response.
With EXISTS:
SELECT p.* FROM PROD p
WHERE EXISTS (
SELECT 1 FROM PROD
WHERE Project = p.Project AND Status = 'B'
)
or with IN:
SELECT * FROM PROD
WHERE Project IN (SELECT Project FROM PROD WHERE Status = 'B')
If you want a solution with JOIN:
SELECT DISTINCT p.*
FROM PROD p JOIN PROD pp
ON pp.Project = p.Project
WHERE pp.Status = 'B'
See the demo.
Results:
> Project | Position | Status
> ------: | -------: | :-----
> 2 | 1 | A
> 2 | 2 | B
> 3 | 1 | B
> 3 | 2 | B
You could try using a join wit the subquery
select * from PROD
INNER JOIN (
select distinct project
from PROD
where status ='B';
) t on t.project = PROD.project
I'm trying to get all the Projects that has at least one Position with Status = B.
No need for a JOIN, just do:
SELECT DISTINCT PROD.Project WHERE PROD.Status='B'
Related
so what I am trying to do is having 3 tables (pictures, collections, and bridge) with the following columns:
Collections Table:
| id | name |
------------------
| 1 | coll1 |
| 2 | coll2 |
------------------
Pictures Table: (timestamps are unix timestamps)
| id | name | timestamp |
-------------------------
| 5 | Pic5 | 1 |
| 6 | Pic6 | 19 |
| 7 | Pic7 | 3 |
| 8 | Pic8 | 892 |
| 9 | Pic9 | 4 |
-------------------------
Bridge Table:
| id | collection | picture |
-----------------------------
| 1 | 1 | 5 |
| 2 | 1 | 6 |
| 3 | 1 | 7 |
| 4 | 1 | 8 |
| 5 | 2 | 5 |
| 6 | 2 | 9 |
| 7 | 2 | 7 |
-----------------------------
And the result should look like this:
| collection_name | picture_count | newest_picture |
----------------------------------------------------
| coll1 | 4 | 8 |
| coll2 | 3 | 9 |
----------------------------------------------------
newest_picture should always be the picture with the heighest timestamp in that collection and I also want to sort the result by it. picture_count is obviously the count of picture in that collection.
Can this be done in a single statement with table joins and if yes:
how can I do this the best way?
A simple method uses correlated subqueries:
select c.*,
(select count(*)
from bridge b
where b.collection = c.id
) as pic_count,
(select p.id
from bridge b join
pictures p
on b.picture = b.id
where b.collection = c.id
order by p.timestamp desc
limit 1
) as most_recent_picture
from collections c;
A more common approach would use window functions:
select c.id, c.name, count(bp.collection), bp.most_recent_picture
from collections c left join
(select b.*,
first_value(p.id) over (partition by b.collection order by p.timestamp desc) as most_recent_picture
from bridge b join
pictures p
on b.picture = p.id
) bp
on bp.collection = c.id
group by c.id, c.name, bp.most_recent_picture;
My database looks like this, I have client accounts which are assigned to specific profiles, and I have profiles which are assigned to specific categories, like in this schema:
| categories | | profiles | | categories_map |
--------------- ------------- ----------------------------
| ID | name | | ID | name | | ID | profile_id | cat_id |
--------------- ------------- ----------------------------
| 1 | cat1 | | 1 | p1 | | 1 | 1 | 1 |
| 2 | cat2 | | 2 | p2 | | 2 | 2 | 1 |
| 3 | cat3 | | 3 | p3 | | 3 | 3 | 1 |
| 4 | p4 | | 4 | 1 | 2 |
| 5 | 3 | 2 |
| 6 | 4 | 3 |
| profiles_map |
-----------------------------
| ID | profile_id | acc_id |
-----------------------------
| 1 | 1 | 1 |
| 2 | 3 | 1 |
| 3 | 4 | 1 |
I need to get categories assigned to accounts - which means when I want to get categories for acc_id = 1, I should get categories with ID 2 and 3 ( category with ID 2 doesn't fit because it contains profile with ID 2 which isn't assigned to this account). I tried this query but it doesn't work
select cats.id from profiles_map map
right join categories_map catm on catm.profile_id = map.profile_id
right join categories cats on cats.id = catm.cat_id
where catm.profile_id in (select profile_id from profiles_map where acc_id = 1)
and map.acc_id = 1 group by cats.id;
Could anybody help me with this question?
Can you try this one?
SELECT DISTINCT C.ID
FROM profiles_map PM
INNER JOIN categories_map CM ON CM.profile_id = PM.profile_id
INNER JOIN categories C ON C.ID = CM.cat_id
WHERE PM.acc_id= 1
If you want to get only category id, Please try following query:
SELECT DISTINCT cm.cat_id FROM categories_map cm
WHERE cm.profile_id in
(SELECT profile_id FROM profiles_map WHERE acc_id = 1)
Or if want to get category name and id then , use following query:
SELECT cat.id,cat.name FROM categories cm
WHERE cat.id in (SELECT DISTINCT cm.cat_id FROM categories_map cm
WHERE cm.profile_id in
(SELECT pm.profile_id FROM profiles_map pm WHERE pm.acc_id = 1))
This must be quite easy, but I cannot find a good solution myself.
I have two tables:
file
+----+--------+
| id | system |
+----+--------+
| 1 | AA |
| 2 | AA |
| 3 | BB |
| 4 | AA |
+----+--------+
feature
+----+---------+------+
| id | file_id | name |
+----+---------+------+
| 1 | 1 | A |
| 1 | 2 | A |
| 1 | 2 | B |
| 1 | 3 | B |
| 1 | 3 | C |
| 1 | 4 | A |
| 1 | 4 | B |
| 1 | 4 | C |
+----+---------+------+
and I want to count how many times a feature was added to files with a specific system. For that, I have the following query:
SELECT f.name, COUNT(*) AS nr
FROM dossier d
JOIN feature f
ON f.file_id = d.id
WHERE d.system = 'AA'
AND d.id NOT IN (3157,3168,3192)
GROUP BY f.name
which gives the desired output:
+------+----+
| name | nr |
+------+----+
| A | 3 |
| B | 2 |
| C | 1 |
+------+----+
Now I also want to know the total amount of files with the same specific system. A simple separate query would be:
SELECT COUNT(*) FROM file WHERE system = 'AA' AND id NOT IN (3157,3168,3192)
I've added the extra AND id NOT IN (which is irrelevant for this example) just to show that the actual query is much more complex. If I use a separate query to get the total I would have to duplicate that complexity, so I want to avoid that by returning the total from the same query.
So how can I count the number of files in the first query?
Desired output:
+------+----+-------+
| name | nr | total |
+------+----+-------+
| A | 3 | 3 |
| B | 2 | 3 |
| C | 1 | 3 |
+------+----+-------+
Here is one way using Sub-query
SELECT f.NAME,
Count(*) AS nr,
(SELECT Count(*)
FROM FILE
WHERE system = 'AA'
AND id NOT IN ( 3157, 3168, 3192 )) as Total
FROM dossier d
JOIN feature f
ON f.file_id = d.id
WHERE d.system = 'AA'
AND d.id NOT IN ( 3157, 3168, 3192 )
GROUP BY f.NAME
Or Use CROSS JOIN
SELECT *
FROM (SELECT f.NAME,
Count(*) AS nr,
FROM dossier d
JOIN feature f
ON f.file_id = d.id
WHERE d.system = 'AA'
AND d.id NOT IN ( 3157, 3168, 3192 )
GROUP BY f.NAME) A
CROSS JOIN (SELECT Count(*) AS Total
FROM FILE
WHERE system = 'AA'
AND id NOT IN ( 3157, 3168, 3192 )) B
I have requirement of getting intersection of some results in mysql DB. But after googling came to know that there is no mysql intersect keyword available . Following are my sample tables.
gene table
+------+--------+---------+
| id | symbol | test_id |
+------+--------+---------+
| -1 | A | -1 |
| 8 | A | 3 |
| 9 | G | 3 |
| -1 | A | -1 |
| -2 | B | -1 |
| -3 | C | -1 |
| 1 | A | 1 |
| 2 | B | 1 |
| 3 | C | 1 |
| 4 | B | 2 |
| 5 | C | 2 |
| 6 | D | 2 |
| 7 | E | 2 |
| 8 | A | 3 |
| 9 | G | 3 |
| 10 | F | 3 |
| 11 | C | 3 |
| 12 | C | 4 |
| 13 | G | 4 |
| 14 | F | 4 |
| 15 | M | 4 |
| 16 | N | 4 |
+------+--------+---------+
test table
+------+-------+
| id | name |
+------+-------+
| -1 | test0 |
| 3 | test3 |
| -1 | test0 |
| 1 | test1 |
| 2 | test2 |
| 3 | test3 |
| 4 | test4 |
+------+-------+
Now I want to formulate a query which will give me the tests which are common for provided genes. e.g. I will provide gene A, B, C and I should get the following result:
id name id symbol
---------------------------
-1 | test0 | -1 | A
-1 | test0 | -2 | B
-1 | test0 | -3 | C
1 | test1 | 1 | A
1 | test1 | 2 | B
1 | test1 | 3 | C
I just tried to form a query by following way but didn't work, getting empty resultset and if I use 'or' in where clause getting tests for all genes in where clause.
select distinct t.id, t.name, g.id, g.symbol from tests t
join genes g on t.id = g.test_id
where g.symbol = 'A' and g.symbol='B' and g.symbol='C';
Please help me to construct the query.
The trick is to filter the records with your criteria, then group by test.id to check that it matches all the criteria:
SELECT t.id
FROM tests AS t
INNER JOIN genes AS g
ON t.id = g.test_id
WHERE g.symbol in ('A','B','C')
GROUP BY t.id
HAVING COUNT(DISTINCT g.symbol) = 3;
So the key line is here:
HAVING COUNT(DISTINCT g.symbol) = 3;
If, like test 2, there is only a match on 'B', then the count will return 1 and the test will be excluded. The number of items you are checking for must match the number in the HAVING clause.
If you then need to get the full data out, you just need to join back to your table:
SELECT t.id, t.name, g.id, g.symbol
FROM genes AS g
INNER JOIN
( SELECT t.id, t.name
FROM tests AS t
INNER JOIN genes AS g
ON t.id = g.test_id
WHERE g.symbol in ('A','B','C')
GROUP BY t.id, t.name
HAVING COUNT(DISTINCT g.symbol) = 3
) t
ON t.id = g.test_id;
Example on SQL Fiddle
Change those AND conditions to OR condition like below cause at any point in time g.symbol can hold only one value and not multiple value. that's why you are getting empty result set.
select t.id, t.name, g.id, g.symbol from tests t
join genes g on t.id = g.test_id
where (g.symbol = 'A' or g.symbol='B' or g.symbol='C')
and g.test_id = 1;
(OR) use a IN operator like
select t.id, t.name, g.id, g.symbol from tests t
join genes g on t.id = g.test_id
where g.symbol in ('A','B','C')
and g.test_id = 1;
I have a source table (piece of it):
+--------------------+
| E M P L O Y E E |
+--------------------+
| ID | EQUIPMENT |
+--------------------+
| 1 | tv,car,phone |
| 2 | car,phone |
| 3 | tv,phone |
+----+---------------+
After normalization process I ended with two new tables:
+----------------+
| DICT_EQUIPMENT |
+----------------+
| ID | EQUIPMENT |
+----------------+
| 1 | tv |
| 2 | car |
| 3 | phone |
+----+-----------+
+---------------------+
| SET_EQUIPMENT |
+----+--------+-------+
| ID | SET_ID | EQ_ID |
+----+--------+-------+
| 1 | 1 | 1 |
| 2 | 1 | 2 |
| 3 | 1 | 3 |
| 4 | 2 | 2 |
| 5 | 2 | 3 |
| 6 | 3 | 1 |
| 7 | 3 | 3 |
+----+--------+-------+
(the piece/part)
+-----------------+
| E M P L O Y E E |
+-----------------+
| ID | EQ_SET_ID |
+-----------------+
| 1 | 1 |
| 2 | 2 |
| 3 | 3 |
+----+------------+
And now when I want to find correct SET_ID I can write something like this:
SELECT SET_ID
FROM SET_EQUIPMENT S1,
SET_EQUIPMENT S2,
SET_EQUIPMENT S3
WHERE S1.SET_ID = S2.SET_ID
AND S2.SET_ID = S3.SET_ID
AND S1.EQ_ID = 1
AND S2.EQ_ID = 2
AND S3.EQ_ID = 3;
Maybe any ideas for optimize this query? how find the correct set?
First, you should use explicit join syntax for the method you are using:
SELECT S1.SET_ID
FROM SET_EQUIPMENT S1 JOIN
SET_EQUIPMENT S2
ON S1.SET_ID = S2.SET_ID JOIN
SET_EQUIPMENT S3
ON S2.SET_ID = S3.SET_ID
WHERE S1.EQ_ID = 1 AND
S2.EQ_ID = 2 AND
S3.EQ_ID = 3;
Commas in a from clause are quite outdated. (And, this fixes a syntax error in your query.)
An alternative method is to use group by with a having clause:
SELECT S.SET_ID
FROM SET_EQUIPMENT S
GROUP BY S.SET_ID
HAVING SUM(CASE WHEN S.EQ_ID = 1 THEN 1 ELSE 0 END) > 0 AND
SUM(CASE WHEN S.EQ_ID = 2 THEN 1 ELSE 0 END) > 0 AND
SUM(CASE WHEN S.EQ_ID = 3 THEN 1 ELSE 0 END) > 0;
Which method works better depends on a number of factors -- for instance, the database engine you are using, the size of the tables, the indexes on the tables. You have to test which method works better on your system.
You've normalised wrongly. Get rid of set_equipment
Change to have three tables: employee, equipment, employee_equipment.
If you're looking for the equipment for a given employee you want to use:
select id, equipment
from equipment eq
inner join employee_equipment ee on eq.id = ee.eq_id
inner join employee emp on emp.id = ee.emp_id
where emp.id = 2