Imagine I have two tables, food and people, and I indicate who likes which food with a link table. So:
foods
-----
sausages
pie
Mars bar
people
------
john
paul
george
ringo
person | food (link table)
-------+-----
john | pie
john | sausage
paul | sausage
I'd like to get a list of foods, along with a person who likes that food. So I'd like a table like this:
food | a randomly chosen liker
---------+------------------------
sausage | john (note: this could be "paul" instead)
pie | john (note: must be john; he's the only liker)
Mars bar | null (note: nobody likes it)
Is it possible to do this in one query?
Obviously, I can do:
select
f.food, p.person
from
food f inner join link l
on f.food = l.food
inner join person p
on l.person = p.person
but that will give me two sausage rows, because two people like it, and I'll have to deduplicate the rows myself.
Do LEFT JOINs to also get food that no-one likes. GROUP BY to get each food only once, use MIN to pick first person that likes that food.
select f.food, min(p.person)
from food f
left join linktable l on f.id = l.food_id
left join people p on p.id = l.person_id
group by f.food
select f.food, min(l.person)
from food f
left join link l on f.foods = l.food
group by f.food
I would use a partition to do that, example:
WITH ORDERED AS
(
SELECT
PERSON,
FOOD,
ROW_NUMBER() OVER (PARTITION BY lower(FOOD) ORDER BY lower(PERSON) DESC) AS RN
FROM
(
SELECT 'john' AS PERSON ,'pie' AS FOOD FROM DUAL UNION
SELECT 'john1' AS PERSON ,'sausage' AS FOOD FROM DUAL UNION
SELECT 'john2' AS PERSON ,'sausage' AS FOOD FROM DUAL UNION
SELECT 'john3' AS PERSON ,'sausage' AS FOOD FROM DUAL UNION
SELECT 'john4' AS PERSON ,'sausage' AS FOOD FROM DUAL UNION
SELECT 'john5' AS PERSON ,'eggs' AS FOOD FROM DUAL UNION
SELECT 'john6' AS PERSON ,'sausage' AS FOOD FROM DUAL UNION
SELECT 'dada' AS PERSON ,'sausage' AS FOOD FROM DUAL UNION
SELECT 'paul' AS PERSON ,'sausage' AS FOOD FROM DUAL
-- Your select statement here that links the two tables
) PERSON_FOOD
)
SELECT
FOOD,
PERSON
FROM
ORDERED
WHERE
RN = 1
This will get you the following:
FOOD | PERSON
-------------------
eggs | john
pie | john
sausage | paul
This is in oracle syntax
Another variant.. (Assuming it is SQL Server )
Select
a.Food, b.Person
from
foods a
outer apply
(
Select top 1 Person from linkTable b where a.Food = b.Food
) b
Related
I'm trying to do some DB during the lockdown and would appreciate some help, since I have been doing this for 5 hours without luck. Got a PDF from a book and sadly, the solutions part isn't readable.
Here are two tables:
**Table 1 named Laptop**
Laptop ID(PK) Name
1 Lenovo
2 Asus
3 Mac
**Table 2 named Buyers**
Buyer ID(PK) Buyer Name Laptop ID(FK) Country
A Jet Li 1 China
B Hermione 1 UK
C Mercato 2 Spain
The activity requests that I create an
"SQL statement that selects all bags names and their buyer name (so 2 columns only), and to show null values as well" because Mac doesn't have a buyer.
I have been trying JOIN and UNION, but no lock.
SELECT Name from Laptop
UNION
SELECT Buyer name from Buyers;
Thank you very much
You need an OUTER JOIN:
SELECT
l.name,
b.buyer_name
FROM
laptop l
LEFT OUTER JOIN buyers b
ON l.laptop_id = b.bag_id;
Demo:
with laptop as(
select 1 laptop_id, 'Lenevo' name from dual union all
select 2 laptop_id, 'Asus' name from dual union all
select 3 laptop_id, 'Mac' name from dual
),
buyers as(
select 'Jet Li' buyer_name, 1 bag_id from dual union all
select 'Hermione' buyer_name, 1 bag_id from dual union all
select 'Mercato' buyer_name, 2 bag_id from dual
)
SELECT
l.name,
b.buyer_name
FROM
laptop l
LEFT OUTER JOIN buyers b
ON l.laptop_id = b.bag_id;
NAME BUYER_NAME
---------- --------------------
Lenevo Jet Li
Lenevo Hermione
Asus Mercato
Mac NULL
Imagine I have two tables, food and people, and I indicate who likes which food with a link table. So:
foods
-----
sausages
pie
Mars bar
people
------
john
paul
george
ringo
person | food (link table)
-------+-----
john | pie
john | sausage
paul | sausage
I'd like to get a list of foods, along with a person who likes that food. So I'd like a table like this:
food | a randomly chosen liker
---------+------------------------
sausage | john (note: this could be "paul" instead)
pie | john (note: must be john; he's the only liker)
Mars bar | null (note: nobody likes it)
Is it possible to do this in one query?
Obviously, I can do:
select
f.food, p.person
from
food f inner join link l
on f.food = l.food
inner join person p
on l.person = p.person
but that will give me two sausage rows, because two people like it, and I'll have to deduplicate the rows myself.
Do LEFT JOINs to also get food that no-one likes. GROUP BY to get each food only once, use MIN to pick first person that likes that food.
select f.food, min(p.person)
from food f
left join linktable l on f.id = l.food_id
left join people p on p.id = l.person_id
group by f.food
select f.food, min(l.person)
from food f
left join link l on f.foods = l.food
group by f.food
I would use a partition to do that, example:
WITH ORDERED AS
(
SELECT
PERSON,
FOOD,
ROW_NUMBER() OVER (PARTITION BY lower(FOOD) ORDER BY lower(PERSON) DESC) AS RN
FROM
(
SELECT 'john' AS PERSON ,'pie' AS FOOD FROM DUAL UNION
SELECT 'john1' AS PERSON ,'sausage' AS FOOD FROM DUAL UNION
SELECT 'john2' AS PERSON ,'sausage' AS FOOD FROM DUAL UNION
SELECT 'john3' AS PERSON ,'sausage' AS FOOD FROM DUAL UNION
SELECT 'john4' AS PERSON ,'sausage' AS FOOD FROM DUAL UNION
SELECT 'john5' AS PERSON ,'eggs' AS FOOD FROM DUAL UNION
SELECT 'john6' AS PERSON ,'sausage' AS FOOD FROM DUAL UNION
SELECT 'dada' AS PERSON ,'sausage' AS FOOD FROM DUAL UNION
SELECT 'paul' AS PERSON ,'sausage' AS FOOD FROM DUAL
-- Your select statement here that links the two tables
) PERSON_FOOD
)
SELECT
FOOD,
PERSON
FROM
ORDERED
WHERE
RN = 1
This will get you the following:
FOOD | PERSON
-------------------
eggs | john
pie | john
sausage | paul
This is in oracle syntax
Another variant.. (Assuming it is SQL Server )
Select
a.Food, b.Person
from
foods a
outer apply
(
Select top 1 Person from linkTable b where a.Food = b.Food
) b
I want to select information from two SQL tables within one query, the information is unrelated though, so no potential joints exist.
An example could be the following setup.
tblMadrid
id | name | games | goals
1 | ronaldo | 100 | 100
2 | benzema | 50 | 25
3 | bale | 75 | 50
4 | kroos | 80 | 10
tblBarcelona
id | name | games | goals
1 | neymar | 60 | 25
2 | messi | 150 | 200
3 | suarez | 80 | 80
4 | iniesta | 40 | 5
I want to have a query that gives me the following:
name | games | goals
messi | 150 | 200
ronaldo | 100 | 100
I tried to follow this logic: Multiple select statements in Single query but the following code did not work:
USE Liga_BBVA
SELECT (SELECT name,
games,
goals
FROM tblMadrid
WHERE name = 'ronaldo') AS table_a,
(SELECT name,
games,
goals
FROM tblBarcelona
WHERE name = 'messi') AS table_b
ORDER BY goals
Any advice on this one? Thanks
Info: The football stuff is just a simplifying example. In reality it is not possible to put both tables into one and have a new "team" column. The two tables have completely different structures, but I need something that matches the characteristics of this example.
You can do something like this:
(SELECT
name, games, goals
FROM tblMadrid WHERE name = 'ronaldo')
UNION
(SELECT
name, games, goals
FROM tblBarcelona WHERE name = 'messi')
ORDER BY goals;
See, for example: https://dev.mysql.com/doc/refman/5.0/en/union.html
If you like to keep records separate and not do the union.
Try query below
SELECT (SELECT name,
games,
goals
FROM tblMadrid
WHERE name = 'ronaldo') AS table_a,
(SELECT name,
games,
goals
FROM tblBarcelona
WHERE name = 'messi') AS table_b
FROM DUAL
The UNION statement is your friend:
SELECT a.playername, a.games, a.goals
FROM tblMadrid as a
WHERE a.playername = "ronaldo"
UNION
SELECT b.playername, b.games, b.goals
FROM tblBarcelona as b
WHERE b.playername = "messi"
ORDER BY goals;
You can union the queries as long as the columns match.
SELECT name,
games,
goals
FROM tblMadrid
WHERE id = 1
UNION ALL
SELECT name,
games,
goals
FROM tblBarcelona
WHERE id = 2
You can combine data from the two tables, order by goals highest first and then choose the top two like this:
MySQL
select *
from (
select * from tblMadrid
union all
select * from tblBarcelona
) alldata
order by goals desc
limit 0,2;
SQL Server
select top 2 *
from (
select * from tblMadrid
union all
select * from tblBarcelona
) alldata
order by goals desc;
If you only want Messi and Ronaldo
select * from tblBarcelona where name = 'messi'
union all
select * from tblMadrid where name = 'ronaldo'
To ensure that messi is at the top of the result, you can do something like this:
select * from (
select * from tblBarcelona where name = 'messi'
union all
select * from tblMadrid where name = 'ronaldo'
) stars
order by name;
select name, games, goals
from tblMadrid where name = 'ronaldo'
union
select name, games, goals
from tblBarcelona where name = 'messi'
ORDER BY goals
Using union will help in this case.
You can also use join on a condition that always returns true and is not related to data in these tables.See below
select tmd .name,tbc.goals from tblMadrid tmd join tblBarcelona tbc on 1=1;
join will help you even in case when tables do not have common columns
You can use UNION in this case
select id, name, games, goals from tblMadrid
union
select id, name, games, goals from tblBarcelona
you jsut have to maintain order of selected columns ie id, name, games, goals in both SQLs
as i see you want most goals in each team
you can try this
select name,games,max(goals) as 'most goals' from tblRealMadrid
union
select name,games,max(goals) as 'most goals' from tblBarcelona
In your case, the two tables have completely different structures and cannot be joined.
The UNION operator could be used. The UNION operator joins the results of two or more SELECT statements to produce a single result set. The first column in the SELECT statement is used to sort the result set.
SELECT name, games, goals
FROM tblMadrid
WHERE name = 'ronaldo'
UNION
SELECT name, games, goals
FROM tblBarcelona
WHERE name = 'messi'
ORDER BY goals;
Each SELECT statement must have the same number of columns and data types that are compatible. Also, if you want to keep the duplicates, use UNION ALL rather than UNION.
I've tried more or less all combinations of count and distinct (except the correct one :) ) in order to get the example below.
Input: table t1
NAME | FOOD
Mary | Apple
Mary | Banana
Mary | Apple
Mary | Strawberry
John | Cherries
Expected output:
NAME | FOOD
Mary | 3
John | 1
N.B. Mary has Apple in two rows but she has 3 as we have 3 different values in the column.
I only managed to get 4 in FOOD Column for her, but I need 3 :(
select a.name as NAME, a.count(name) as Food
from
(SELECT distinct NAME,Food from table)a
Start with a query which gives you unique combinations of NAME and FOOD:
SELECT DISTINCT t1.NAME, t1.FOOD
FROM t1
Then you can use that as a subquery in another where you can GROUP BY and Count:
SELECT sub.NAME, Count(*) AS [FOOD]
FROM
(
SELECT DISTINCT t1.NAME, t1.FOOD
FROM t1
) AS sub
GROUP BY sub.NAME;
select a.name, sum(a.FoodCount) from(
select distinct name,COUNT(food) as FoodCount from #t1 group by name, food ) as a group by a.name order by 2 desc
I have a SQL Server 2008 database. In this database, I have a result set that looks like the following:
ID Name Department LastOrderDate
-- ---- ---------- -------------
1 Golf Balls Sports 01/01/2015
2 Compact Disc Electronics 02/01/2015
3 Tires Automotive 01/15/2015
4 T-Shirt Clothing 01/10/2015
5 DVD Electronics 01/07/2015
6 Tennis Balls Sports 01/09/2015
7 Sweatshirt Clothing 01/04/2015
...
For some reason, my users want to get the results ordered by department, then last order date. However, not by department name. Instead, the departments will be in a specific order. For example, they want to see the results ordered by Electronics, Automotive, Sports, then Clothing. To throw another kink in works, I cannot update the table schema.
Is there a way to do this with a SQL Query? If so, how? Currently, I'm stuck at
SELECT *
FROM
vOrders o
ORDER BY
o.LastOrderDate
Thank you!
You can use case expression ;
order by case when department = 'Electronics' then 1
when department = 'Automotive' then 2
when department = 'Sports' then 3
when department = 'Clothing' then 4
else 5 end
create a table for the departments that has the name (or better id) of the department and the display order. then join to that table and order by the display order column.
alternatively you can do a order by case:
ORDER BY CASE WHEN Department = 'Electronics' THEN 1
WHEN Department = 'Automotive' THEN 2
...
END
(that is not recommended for larger tables)
Here solution with CTE
with c (iOrder, dept)
as (
Select 1, 'Electronics'
Union
Select 2, 'Automotive'
Union
Select 3, 'Sports'
Union
Select 4, 'Clothing'
)
Select * from c
SELECT o.*
FROM
vOrders o join c
on c.dept = o.Department
ORDER BY
c.iOrder