I have the following table:
Name Product
Bob Car
Bob Apples
Bob Pears
Bob Car
John Apples
John Pears
Whoever has bought a Product Car, I want to keep separate from everyone else. So, I create a flag:
Name Product Flag
Bob Car 1
Bob Apples 0
Bob Pears 0
Bob Car 1
John Apples 0
John Pears 0
But the problem with my flag is that even if I do a where condition and say, show me the consumer WHERE flag !=1, it'll pick Bob. Which is incorrect as Bob owns a car.
I would still like to GROUP by Product.
How do I separate the above table into two groups?
Thanks!
Use below query :-
select name from table where flag!=1
and name not in (select name from table where flag = 1)
group by name
"show me the consumer WHERE flag !=1, it'll pick Bob" that is because you are asking for rows where flag != 1. Instead you'll need something a little more complicated, like:
SELECT DISTINCT Name
FROM tableTable
WHERE Name NOT IN (SELECT Name FROM theTable WHERE Product = 'Car')
alternatively, you can do a LEFT JOIN, which may or may not be faster depending on the amount of data you have and how its values are distributed.
SELECT DISTINCT a.Name
FROM theTable a
LEFT JOIN theTable b ON a.Name = b.Name AND b.Product = 'Car'
WHERE a.Product != 'Car' AND b.Product IS NULL
;
This gets all the rows with products other than cars, and then uses the LEFT JOIN in conjunction with the IS NULL condition to find which did not also have a 'Car' row.
I think you want your table's data displayed, just with "People who bought cars" partitioned (not grouped) separately somehow - this could be done with an ORDER BY OwnsACar clause, for example.
Step 1: Identify the people who have bought cars:
SELECT DISTINCT
Name
FROM
yourTable
WHERE
Product = 'Car'
Step 2: Join on this data to generate a calculated "OwnsACar" column:
SELECT
yourTable.Name,
yourTable.Product,
ISNULL( carowners.Name ) AS OwnsACar
FROM
yourTable
LEFT OUTER JOIN
(
SELECT DISTINCT
Name
FROM
yourTable
WHERE
Product = 'Car'
) AS carowners ON carowners.Name = yourTable.Name
ORDER BY
OwnsACar ASC,
yourTable.Name ASC
You can use these two queries. The additional Flag column is not required.
-- do not have Car
SELECT *
FROM products
WHERE Name not in (SELECT DISTINCT Name
FROM products
WHERE Product='Car');
-- have Car
SELECT *
FROM products
WHERE Name in (SELECT DISTINCT Name
FROM products
WHERE Product='Car');
Illustration:
-- table
SELECT * FROM products;
+------+---------+
| Name | Product |
+------+---------+
| Bob | Car |
| Bob | Apples |
| Bob | Pears |
| Bob | Car |
| John | Apples |
| John | Pears |
+------+---------+
-- query for people that do not have Car
+------+---------+
| Name | Product |
+------+---------+
| John | Apples |
| John | Pears |
+------+---------+
-- query for people having 'Car'
+------+---------+
| Name | Product |
+------+---------+
| Bob | Car |
| Bob | Apples |
| Bob | Pears |
| Bob | Car |
+------+---------+
Try with :
SELECT `t`.`Name`, `t`.`Product`, SUM(`t`.`Flag`) as hasCar
FROM your_table t
GROUP BY `t`.`Name`
HAVING `t`.`hasCar` = 0;
Although you can go without the flag column by going :
SELECT `t`.`Name`, `t`.`Product`, SUM(IF(`t`.`Product` = 'Car', 1, 0)) as hasCar
FROM your_table t
GROUP BY `t`.`Name`
HAVING `t`.`hasCar` = 0;
Related
I have a table with users and countries either UK or US, now a user can appear multiple times with a different country. I need to select a list with unique users with their country either equal to UK, US or BOTH.
This is the approach Im trying but it doesn't appear to be working.
select user,
case
when COUNT(*) <= 1 and count(select where = "UK") = count(*) then "UK"
when COUNT(*) <= 1 and count(select where = "US") = count(*) then "US"
when COUNT(*) <= 1 and count(select where = "US") != count(*) then "BOTH"
END CASE
as country from users;
First time using logic like this in a query so sorry for sounding like a noob.
+------------------------------+-------------+
| user | country |
+------------------------------+-------------+
| John | US |
| Jack | US |
| John | UK |
| Joe | US |
| John | UK |
| Jacky | US |
+------------------------------+-------------+
You could do something like:
SELECT
temp.user,
if(temp.CountryList = "UK,US", "BOTH", temp.CountryList) as country
FROM
(
SELECT
user,
group_concat(DISTINCT country ORDER BY country) as CountryList
FROM USERS
GROUP BY user
) temp
The title is a bit wrong, i can explain better here.
Say i have a MySQL table like this:
mysql> select * from people;
+------+---------------+
| name | number |
+------+---------------+
| John | 100000 |
| Alex | 200000 |
| Tim | 500000 |
| Alice| 100000 |
| Peter| 500000 |
+------+---------------+
And now i want a query which returns the names of the people who have the same number, ie, for this table i would a query which would return John and Alice (they have the same number, 100000) and Tim and Peter (the same number 500000)
Try self join as below:
SELECT p1.name
FROM people p1 INNER JOIN people p2
ON p1.number = p2.number
WHERE p1.name != p2.name
You can do this by aggregating on the number column and using group_concat(). A having clause selects only cases where there is more than one name:
select number, group_concat(name) as names
from table t
group by number
having count(*) > 1;
I have 2 tables in MySQL, in both of these tables I have merchant_id, merchant, branch and some another fields, the name of one table is merchant and another table is product.
tbl_merchant :
id | merchant_id | merchant_name | branch | ...
------+---------------+--------------------+----------------+
1 | 1001 | McDonalds | branch 1 mcd | ...
2 | 2002 | KFC | branch 1 kfc | ...
tbl_product :
id | product_id | product_name | price | merchant_id
------+---------------+-----------------+---------+-------------
1 | 100101 | Chicken | 10 | 1001
2 | 100102 | Potato | 5 | 1001
3 | 100101 | Burger | 10 | 2002
4 | 100102 | Fish Fillet | 10 | 2002
I want to know how can to show merchant_name, branch from both tables using SQL WHERE Clause by product_id = 100101 and merchant_id = 1001 ?
Like this :
Result :
id | merchant | branch | product_name | price
------+-------------+----------------+---------------+-------
1 | McDonalds | branch 1 mcd | Chicken | 10
Thank You
First, I'll show you the query, then I'll explain each part line by line to help you understand:
SELECT
merchant_name, branch
FROM
tbl_merchant INNER JOIN tbl_product ON (tbl_product.merchant_id = tbl_merchant.merchant_id)
WHERE
product_id = 100101 AND merchant_id = 1001
Alright, so if we look at the first part following the select, it should be clear that the two columns that will be printed out are merchant_name and branch. Based on your output, you can print out any field from either table just by adding its name to the list. If the field has the same name in both tables, then you need to qualify it like this:
SELECT
tbl_merchant.id, tbl_product.id
FROM
tbl_merchant INNER JOIN tbl_product USING(merchant_id)
The tricky part of this query is the line that joins the two tables together. Essentially what you have as of now is two tables that are linked together by a merchant id, which makes sense because 1 merchant can have many products (i.e. a 1 to many relationship). I'm assuming that the merchant ID is unique. The join then pairs together all the rows that have the same merchant_id (which is unique in one of the tables and therefore guaranteed to be correct). More specially you can think of it as a qualified cross product where each tuple from tbl_product is joined with each tuple from tbl_merchant and then qualified based on the condition tbl_product.merchant_id = tbl_merchant.merchant_id.
The last part of the query (WHERE clause) simply eliminates rows based on the conditions provided.
The query for this is:
SELECT merchant_name, branch
FROM
tbl_merchant
INNER JOIN
tbl_product
ON (tbl_product.merchant_id = tbl_merchant.merchant_id)
WHERE
product_id = 100101 AND merchant_id = 1001
SELECT merchants.id, merchants.merchant_id, merchants.branch, products.product_name, products.price
FROM merchants
INNER JOIN products ON products.merchant_id = merchants.merchant_id
WHERE merchants.merchant_id = 1001 AND products.product_id = 100101
you can use JOIN to solve this type of query
there are some good article to learn more about JOIN with visula explanation::
1) http://blog.codinghorror.com/a-visual-explanation-of-sql-joins/ "A Visual Explanation of SQL Joins"
2) http://www.codeproject.com/Articles/33052/Visual-Representation-of-SQL-Joins "Visual Representation of SQL Joins"
Try this:
select * from marchant join product on marchant.id=product.merchant_id where merchant_id = 1001
This statement will join both tables together where the primary key form merchant is equals the merchant_id in product.
THIS is the table for the questions
+---------+----------+------+
| owner | species | sex |
+---------+----------+------+
| Harry | cat | f |
| Gwen | dog | m |
| Adlai | rat | m |
| Alex | bird | f |
| Harry | dog | f |
| Gwen | cat | m |
| Gwen | dog | f |
+---------+----------+------+
I have tried >
SELECT owner,MAX(count(species)) FROM pet GROUP BY owner;
did not get it.
i managed to get >
SELECT owner, count(species) FROM pets GROUP BY owner;
+---------+----------------+
| owner | count(species) |
+---------+----------------+
| Gwen | 3 |
| Adlai | 1 |
| Harry | 2 |
| Alex | 1 |
+---------+----------------+
but it needs only one...
please help!
Thanks!
1.
SELECT owner
FROM pet
WHERE species IN ('cat', 'dog')
GROUP BY owner
HAVING COUNT(*) = 2
This query assumes the owner can only have a single cat and a single dog.
1a.
SELECT p1.owner
FROM pet p1
INNER JOIN p2 ON p1.owner = p2.owner
AND p2.pet = 'dog'
WHERE p1.pet = 'cat'
GROUP BY p1.owner
This query is slightly better since it doesn't care of how many pets every owner has.
2.
SELECT owner, count(species) cnt
FROM pets
GROUP BY owner
ORDER BY count(species) DESC
LIMIT 1
PS: and try to do your homework next time by yourself ;-)
Instead of hard-coding specific species, what it looks like you are asking for is... Of the owners of pets, I want to know who has the most distinct species regardless of sexual gender (m/f). Whatever that count is, you want to list all owners who had that # of species. Start first with getting the highest distinct species count per ANY owner, ANY species...
However, by re-reading, it looks like you are considering Gwen as 3 species even though 2 are dogs, 1 is a cat, but the dogs are one male, one female... What if someone has 4 dogs and they are all male and 5 cats all female. Would that count as 2 species?
Anyhow, based on my original based on distinct SPECIES (regardless of gender), I have a solution
select
PreQuery.owner,
PreQuery.SpeciesCount,
#HighCount := if( #HighCount < PreQuery.SpeciesCount,
PreQuery.SpeciesCount, #HighCount ) as KeepCount
from
( select
owner,
count( distinct species ) as SpeciesCount
from
pets
group by
owner
order by
count( distinct species ) desc ) PreQuery,
( select #HighCount := 0 ) sqlvars
having
SpeciesCount = KeepCount
at SQL Fiddle
The first query pre-aggregates the number of DISTINCT species regardless of gender and orders with the highest count coming first. By using MySQL Variables (via #varName), I am applying the first record returned in the result set to the high count value, then keep it there for all subsequent records.
Finally, the "HAVING" clause allows it to retain only those that had that max count.. in this scenario, it had TWO people with two distinct species.
If you DO want it based on species AND sex, we can revise the query, but the principle will be the same.
Another query based on distinct species AND sex
I just changed to
count( distinct concat(species, sex) )
in both places
The case:
I have 2 tables, 'contracts' and 'members' tied with contract.id = members.cid.
Each contract has one main member and several secondary members (usually the children and spouse of the main member). The main member's details (name, address etc) are stored in table contracts whereas, extra members details are kept in table members. (bad logic, i know but this was a mess to begin with and i need time to redesign the db and website)
The desired output:
When I run a batch print of all contracts (lets say, every Friday) I need to also print a copy of the contract for each member, too but with the member's details on the contract instead of the main member.
The question:
How does this translate into a mysql query? Ok, its a left join, but how do I say "print data from table members instead of contracts for the joined rows"?
Main fields that occur in the 2 tables are name + surname, those should be enough for a draft query example.
Example tables and data:
contracts
-------------------------
id | name | surname |
-------------------------
1 | Tom | Jones |
2 | Jamie | Oliver |
members
--------------------------------
id | cid | name | surname |
--------------------------------
1 | 1 | Jack | Jones |
2 | 1 | Anne | Jones |
3 | 2 | Cathy | Wilson |
So the results I want shoudld be:
cid | name | surname |
--------------------------
1 | Tom | Jones |
1 | Jack | Jones |
1 | Anne | Jones |
2 | Jamie | Oliver |
2 | Cathy | Wilson |
If i write
SELECT c.name as name, c.surname as surname, m.name as name, m.surname as surname
FROM contracts c
join members m on c.id = m.cid
I simply end up with
name and name_1, surname and surname_1 but I want ALL names to fall under name and likewise for all other matching columns.
Hope this works :::
select c1.id, c1.name, c1.surname
from contracts c1
union
(Select m.id, m.name, m.surname
from
members m left join contracts c on (c.id = m.cid))
This is what I finally did and it worked (field names are different but the syntax is what matters):
SELECT u.id, u.onoma_u, u.name_u,
coalesce(u.programa, aa.programa) as programa,
coalesce(u.barcode, aa.barcode) as barcode,
coalesce(u.plan, aa.plan) as plan,
coalesce(u.im_exp, aa.im_exp) as im_exp,
coalesce(u.symb, aa.symb) as symb
FROM (SELECT a1.id, a1.onoma_u, a1.name_u, a1.programa, a1.barcode, a1.plan, a1.im_exp, a1.symb
FROM aitisi a1
UNION
SELECT a2.id, m.name, m.surname, NULL, NULL, NULL, NULL, NULL
FROM members m
JOIN aitisi a2 ON a2.id = m.symbid) u
JOIN aitisi aa ON aa.id = u.id;
I used aliases and NULLS as dummy fields to fill in the blanks.