I have the following table with duplicate family IDs but different number of family members:
tbl_family
+------------+--------------+---------+
| familyID | Members | Location|
+------------+--------------+---------+
| 100 | 3 | xyz |
| 100 | 4 | xyz |
| 101 | 1 | abc |
| 101 | 2 | abc |
| 102 | 5 | efg |
| 103 | | hij |
+------------+--------------+---------+
I also have a second table where we verified the correct count of family members for the duplicates
tbl_verifier
+------------+--------------+---------+
| familyID | Members | Location|
+------------+--------------+---------+
| 100 | 3 | xyz |
| 101 | 2 | abc |
+------------+--------------+---------+
I want to create a view in mysql which will display the families without duplicates and maintain the row with the verified count of family members. The results should look as follows:
tbl_results
+------------+--------------+---------+
| familyID | Members | Location|
+------------+--------------+---------+
| 100 | 3 | xyz |
| 101 | 2 | abc |
| 102 | 5 | efg |
| 103 | | hij |
+------------+--------------+---------+
I am breaking the problem into several steps. I want to first select all those with matching Members then those with null Members
/* Step 1: Select only those that are matching family members count in
verifier and family */
select *
from tbl_family f
inner join
tbl_verifier v
ON f.familyID = v.familyID
WHERE f.Members = v.Members;
/* Step 2 : Select only those that have null number of rooms*/
select *
from tbl_family f
left join
tbl_verifier v
ON f.familyID = v.familyID
WHERE f.Members is null
Now am a bit stuck on how to proceed further.
Use UNION All to merge two result sets
select *
from tbl_family f
inner join tbl_verifier v ON f.familyID = v.familyID
and f.Members = v.Members
union all
select * from tbl_family f
left join tbl_verifier v ON f.familyID = v.familyID and and f.Members = v.Members
where v.familyID is null
how that sounds? I think it works
SELECT f.*
FROM tbl_family f, tbl_verifier v
WHERE (f.familyID = v.familyID AND f.Members = v.Members)
OR f.familyID NOT IN (SELECT familyID FROM tbl_verifier)
Use UNION ALL for your case, but it is better to add a location filter for same.
; with cte as (
select tbl_family.family_id, tbl_family.Members, tbl_family.location
from tbl_family
inner join tbl_verifier ON tbl_family.familyID = tbl_verifier.familyID
and tbl_family.Members = tbl_verifier.Members and tbl_family.Location = tbl_verifier.Location
union all
select tbl_family.family_id, tbl_family.Members, tbl_family.location
from tbl_family
left join tbl_verifier ON tbl_family.familyID = tbl_verifier.familyID
where tbl_family.Members is null
)
Select * from cte order by family_id
UNION ALL seems like a reasonable solution. The big question is how to get one row out of the first table if there are multiple rows.
Here is one method that uses MAX():
select v.familyID, v.Members, v.Location
from tbl_verifier v
union all
select f.familyID, max(f.Members), f.Location
from tbl_family f
where not exists (select 1
from tbl_verifier v
where v.familyId = f.familyId
);
Your question is unclear as to whether families can be in multiple locations. If so, you need to include location in the correlation clause.
From the different answers posted above, i was able to come up with the following script which worked
; with cte as (select f.familyID,
f.Members,
f.Location
from tbl_family f
inner join tbl_verifier v ON f.familyID = v.familyID
and f.Members = v.Members
union all
select f.familyID,
f.Members,
f.Location from tbl_family f
left join tbl_verifier v ON f.familyID = v.familyID
where f.Members is NULL
)
SELECT * INTO temp1 FROM cte
SELECT * FROM tbl_family WHERE familyID NOT IN (SELECT familyID FROM temp1)
UNION ALL
SELECT * FROM temp1
ORDER BY familyID
Related
What is the right way to select films which labels are 'Action' AND 'Drama' using INNER JOIN ?
I've tried this query, the result must be 'Taken, The Godfather' but, no result returned.
SELECT
f.film_guid,
f.film_name
FROM
films as f
INNER JOIN
film_labels as l ON l.film_guid = f.film_guid
WHERE
l.label = 'Action' AND l.label = 'Drama'
Table: films
+------------+----------------+
| film_guid | film_name |
+------------+----------------+
| filmguid_1 | Taken |
| filmguid_2 | Matrix |
| filmguid_3 | The Godfather |
+------------+----------------+
Table: film_labels
+------------+----------------+
| film_guid | label |
+------------+----------------+
| filmguid_1 | Action |
| filmguid_1 | Drama |
| filmguid_1 | Family |
| filmguid_2 | Action |
| filmguid_3 | Action |
| filmguid_3 | Drama |
+------------+----------------+
You are looking for a rows in film_labels that contains both Action and Drama, which cannot happen. You need to search across labels that correspond to the given film, which suggest aggregation:
SELECT f.film_guid, f.film_name
FROM films as f
INNER JOIN film_labels as l ON l.film_guid = f.film_guid
WHERE l.label IN ('Action', 'Drama') -- either one, or the other
GROUP BY f.film_guid, f.film_name
HAVING COUNT(*) = 2 -- both match
Note that you could also use exists with correlated subquery. It is a bit longer to type but could be more efficient (with the right indexes in place), since it avoids the need for aggregation:
SELECT f.*
FROM films as f
WHERE
EXISTS (SELECT 1 FROM film_labels l WHERE l.film_guid = f.film_guid AND l.label = 'Action')
AND EXISTS (SELECT 1 FROM film_labels l WHERE l.film_guid = f.film_guid AND l.label = 'Drama')
For performance with the second query, you want an index on film_labels(film_guid , label).
How do I build a joint to select either table
Table jobs
Id | name | salary | company | type
1 | php | 17.850 | 5 | 1
2 | mysql | 4.500 | 89 | 2
2 | nodejs | 7.500 | 89 | 1
Table Company
Id | name | Area | status
1 | Facebook| Developer| 1
2 | Google | Manager | 1
Table Candidate
Id | name | City | phone
1 | Alan Kout | Nevada | 1 555 6666
2 | Wagner Mom | L.A. | 1 444 8965
My query mysql, inner join candidate or company
If type == 1 in table jobs INNER JOIN ON table company
If type == 2 in table jobs INNER JOIN ON table candidate
Example
SELECT * FROM table_jobs
IF(table_jobs.type == 1, INNER JOIN table_company, INNER JOIN table_candidate)
This is possible?
You can achieve this using a LEFT JOIN instead of an INNER JOIN:
SELECT *
FROM table_jobs tj
LEFT JOIN table_company tco ON tj.type = 1 AND tco.id = tj.id
LEFT JOIN table_candidate tca ON tj.type = 2 AND tca.id = tj.id
This will join to table_company where the type is 1, and table_candidate where the type is 2.
You can then SELECT whichever columns are needed from each table as appropriate.
Use left join and coalesce():
SELECT tj.*,
coalesce(co.name, ca.name) as name,
. . .
FROM table_jobs tj LEFT JOIN
table_company co
ON co.id = tj.id and tj.type = 1 LEFT JOIN
table_candidate ca
ON ca.id = tj.id and tj.type = 2;
If you want both joins in one result you can use the UNION operator
SELECT *
FROM table_jobs INNER JOIN table_company
WHERE table_jobs.type=1
UNION
SELECT *
FROM table_jobs INNER JOIN table_candidate
WHERE table_jobs.type=2
I have tables books and bookType which pose a 1 X n relationship.
books
+-----+------------------+----------+-------+
| id | title | bookType | price |
+-----+------------------+----------+-------+
| 1 | Wizard of Oz | 3 | 14 |
| 2 | Huckleberry Finn | 1 | 16 |
| 3 | Harry Potter | 2 | 25 |
| 4 | Moby Dick | 2 | 11 |
+-----+------------------+----------+-------+
bookTypes
+-----+----------+
| id | name |
+-----+----------+
| 1 | Fiction |
| 2 | Drama |
| 3 | Children |
+-----+----------+
How would I retrieve bookTypes where all books are more expensive than e.g. 12($)?
In this case, the expected output would be:
+-----+----------+
| id | name |
+-----+----------+
| 1 | Fiction |
| 3 | Children |
+-----+----------+
You can use not exists:
select t.*
from bookTypes t
where not exists (
select 1
from books b
where b.bookType = t.id and b.price < 12
)
If you want to select book types that also have at least one associated book:
select t.*
from bookTypes t
where
exists (select 1 from books b where b.bookType = t.id)
and not exists (select 1 from books b where b.bookType = t.id and b.price < 12)
Do a GROUP BY, use HAVING to return only booktypes having the lowest price > 12.
SELECT bt.name
FROM bookTypes bt
INNER JOIN books b ON b.bookType = bt.id
group by bt.name
HAVING SUM(b.price <= 12) = 0;
You can directly consider using having min(price) >= 12 with grouping by bookType
select t.id, t.name
from bookTypes t
join books b
on t.id = b.bookType
group by b.bookType
having min(price) >= 12
Moreover, if your DB's version is at least 10.2, then you can also use some window functions for analytical queries such as min(..) over (partition by .. order by ..) :
with t as
(
select t.id, t.name, min(price) over (partition by bookType) as price
from bookTypes t
join books b
on t.id = b.bookType
)
select id, name
from t
where price >= 12
in which min() over (..) window function determines minimum price for each booktype by use of partition by bookType
Demo
I think GMB's solution is likely the best so far. But for sake of completeness: You can also use the ALL operator with a correlated subquery. That's probably the most straight forward solution.
SELECT *
FROM booktypes bt
WHERE 12 < ALL (SELECT b.price
FROM books b
WHERE b.booktype = bt.id);
Can you not just select from books inner join bookTypes on id WHERE price > 12?
SELECT bt.*
FROM bookTypes bt
INNER JOIN books b ON b.bookType = bt.id
WHERE b.price > 12
I have the following MySQL-Statement:
SELECT norm.NormID, norm.NormName
FROM (assignment
INNER JOIN norm
ON assignment.NID = norm.NormID )
INNER JOIN wire
ON assignment.LID = wire.WireID
WHERE wire.WireID= 109
ORDER BY norm.NormName;
Now what I got are the entries from the table assignment with the NormID and NormName for that WireID.
What I want to get are the entries from the table norm, which are not setted for this WireID.
E.g.:
WireID has the norm assignment A, B, D, G.
The table norm has the entries A, B, C, D, E, F, G, H.
What I want to get from the MySQL-Statment are the entries C, E, F, H.
How can I select those left norm entries for this WireID?
With the above statement I would get:
-----------------------
| NormID | NormName |
-----------------------
| 1 | A |
| 2 | B |
| 4 | D |
| 7 | G |
-----------------------
I want to have this Table:
-----------------------
| NormID | NormName |
-----------------------
| 3 | C |
| 5 | E |
| 6 | F |
| 8 | H |
-----------------------
I think (if I understood what you asked) you can try this :
SELECT norm.NormID, norm.NormName
FROM assignment
INNER JOIN norm ON assignment.NID = norm.NormID
LEFT JOIN wire ON assignment.LID = wire.WireID
WHERE assignment.LID= 109
AND wire.wireID IS NULL
ORDER BY norm.NormName;
Edit after your comments.
I think you could use:
SELECT A.NormID, A.NormName
FROM norm A
LEFT JOIN (SELECT NID FROM assignment WHERE LID = 109) B ON B.NID = A.NormID
WHERE B.NID IS NULL
ORDER BY A.NormName;
OR
SELECT A.NormID, A.NormName
FROM norm A
WHERE NOT EXISTS (SELECT 1 FROM assignment WHERE LID = 109 AND ASSIGNMENT.NID = A.NormID)
ORDER BY A.NormName;
Try this:
select norm.NormID,norm.NormName from norm
Inner JOIN
assignment on assignment.NID = norm.NormID
where assignment.LID in(select wireID from Wire where WireID = 109)
Im not so sure coz i dont have your data
after you added a sample data the entries that are not setted with 109 wireid are these:
SELECT norm.NormID, norm.NormName
FROM assignment
inner JOIN norm
ON assignment.NID = norm.NormID
INNER JOIN wire
ON assignment.LID = wire.WireID
WHERE wire.WireID <> 109
ORDER BY norm.NormName;
i have table of members
table members :
pid| id | name
1 | id01 | jenny
2 | id02 | kain
3 | id03 | alex
and have another table members_opt
table members_opt
pid | members_id | category
1 | id01 | cat
2 | id01 | dog
3 | id02 | dog
4 | id03 | NULL
now i use below SQL query
SELECT * FROM members a JOIN
(SELECT members_id, max(category) as category FROM members_opt GROUP BY members_id) b
ON a.id = b.members_id
But this SQL Query not catch "id03"'s data because "id03"'s members_opt.category is NULL
I want this result
result :
id | name | category
id01 | jenny | cat
id02 | kain | dog
id03 | alex | NULL
(the result now showed double name, double id value.)
How can i use SQL query?
You can try this -
SELECT * FROM members a JOIN
(SELECT members_id, max(CASE WHEN category IS NULL THEN 0) as category FROM members_opt GROUP BY members_id) b
ON a.id = b.members_id
Use the below query to get your desired output -
SELECT a.id, a.name, b.category FROM members a INNER JOIN
(SELECT members_id, category FROM members_opt GROUP BY members_id) b
ON a.id = b.members_id
Just change JOIN to LEFT JOIN :
SELECT a.id, a.name, b.category
FROM members a
LEFT JOIN (
SELECT members_id, max(category) as category
FROM members_opt GROUP BY members_id) b
ON a.id = b.members_id
and if you want 'cat' for 'jenny', you should use aggregation function min.