SELECT DISTINCT return duplicated values - mysql

I have 3 tables players positions players_national
I need to SELECT DISTINCT positions for players_national where player_positon is associated with players table.
My Tables are like this:
Players Table
-----------------------------------------------------------------------
| player_id player_name player_team player_position |
-----------------------------------------------------------------------
1 KAKA 12 1
2 Ronaldo 7 2
3 Adriano 10 2
Positions Table
-------------------------------------------------------
| position_id position_name |
-------------------------------------------------------
1 Midfield
2 Forward
Players_national Table
-------------------------------------------------------------------
| player_id player_team player_national_team |
-------------------------------------------------------------------
1 12 4
2 7 4
3 19 4
My Dream output is this
---------------------------------------------------
| player_national_team position |
---------------------------------------------------
4 1
4 2
My Query is like this:
SELECT DISTINCT players. * , positions. * , players_national. *
FROM players
LEFT JOIN positions ON positions.position_id = players.player_position
LEFT JOIN players_national ON players_national.player_id = players.player_id
WHERE players_national.player_id = players.player_id AND players_national.player_national_team = 4

If you select everything from every table then every row will be DISTINCT; you need to limit your SELECT clause to just the fields you want to be DISTINCT
SELECT DISTINCT positions.position_id, players_national.player_national_team
FROM players
LEFT JOIN positions ON positions.position_id = players.player_position
LEFT JOIN players_national ON players_national.player_id = players.player_id
WHERE players_national.player_id = players.player_id AND players_national.player_national_team = 4

Distinct player_position on table players, where is join to table players_national
SELECT
DISTINCT(players.player_position),
players_national.player_national_team
FROM players INNER JOIN players_national;
result:
+-----------------+----------------------+
| player_position | player_national_team |
+-----------------+----------------------+
| 1 | 4 |
| 2 | 4 |
+-----------------+----------------------+
2 rows in set

Related

How to join 5 tables MYSQL with specific condition

i have 5 tables below
tb_satker
kdsatker
1
2
3
tb_akun
akun | code
A | 1
B | 2
C | 3
tb_simponi
kdsatker | akun | jumlah
1 | A | 100
1 | B | 200
tb_span
kdsatker | akun | jumlah
1 | A | 1
1 | B | 2
1 | C | 3
tb_upt
kdsatker | akun | jumlah
1 | A | 10
1 | B | 20
1 | C | 30
What i need is output to something like this
kdsatker | akun | simponi | span | upt
1 | A | 100 | 1 | 10
1 | B | 200 | 2 | 20
1 | C | 0 | 3 | 30
2 | 0 | 0 | 0 | 0
3 | 0 | 0 | 0 | 0
I've try using sql fiddle but the result is not right (http://sqlfiddle.com/#!9/e83ce7/10)
SELECT tb_satker.kdsatker,tb_akun.akun,tb_simponi2.simponi,tb_span2.span,tb_upt2.upt
FROM tb_satker
LEFT JOIN (SELECT kdsatker,akun,sum(tb_simponi.jumlah) as simponi FROM tb_simponi GROUP BY kdsatker,akun)
as tb_simponi2 ON tb_simponi2.kdsatker=tb_satker.kdsatker
LEFT JOIN (SELECT kdsatker,akun,sum(tb_span.jumlah) as span FROM tb_span GROUP BY kdsatker,akun)
as tb_span2 ON tb_span2.kdsatker=tb_satker.kdsatker
LEFT JOIN (SELECT kdsatker,akun,sum(tb_upt.jumlah) as upt FROM tb_upt GROUP BY kdsatker,akun)
as tb_upt2 ON tb_upt2.kdsatker=tb_satker.kdsatker
LEFT JOIN
tb_akun ON tb_akun.akun=tb_simponi2.akun AND
tb_akun.akun=tb_span2.akun AND
tb_akun.akun=tb_upt2.akun
GROUP BY tb_satker.kdsatker,tb_akun.akun
Can anybody help me with the right idea??
Many Thanks
Your inner queries are all based on a two-part group by two parts... kdsatker and akun.
Since it is possible for any of the tb_simponi, tb_span, tb_upt can have any combination,
I would pre-union all possible combinations of those FIRST. THEN, Join to the summary results.
and FINALLY get the akun and kdsatker components. Something like...
SELECT
tb_satker.kdsatker,
coalesce( tb_akun.akun, 0 ) akun,
coalesce( tb_simponi2.simponi, 0 ) simponi,
coalesce( tb_span2.span, 0 ) span,
coalesce( tb_upt2.upt, 0 ) upt
FROM
tb_satker
LEFT JOIN
( SELECT distinct kdsatker, akun FROM tb_simponi
UNION
SELECT kdsatker, akun FROM tb_span
UNION
SELECT kdsatker, akun FROM tb_upt
) AllKdAkun
on tb_satker.kdsatker = AllKdAkun.kdsatker
LEFT JOIN tb_akun
on AllKdAkun.akun = tb_akun.akun
LEFT JOIN
(SELECT kdsatker, akun, sum(tb_simponi.jumlah) as simponi
FROM tb_simponi
GROUP BY kdsatker, akun ) as tb_simponi2
ON AllKdAkun.kdsatker = tb_simponi2.kdsatker
AND AllKdAkun.Akun = tb_simponi2.akun
LEFT JOIN
(SELECT kdsatker, akun, sum(tb_span.jumlah) as span
FROM tb_span
GROUP BY kdsatker, akun ) as tb_span2
ON AllKdAkun.kdsatker = tb_span2.kdsatker
AND AllKdAkun.akun = tb_span2.akun
LEFT JOIN
(SELECT kdsatker, akun, sum(tb_upt.jumlah) as upt
FROM tb_upt
GROUP BY kdsatker, akun) as tb_upt2
ON AllKdAkun.kdsatker = tb_upt2.kdsatker
AND AllKdAkun.akun = tb_upt2.akun
No final group by at the outer level.
First level is your tb_satker. There may (or not) be a record in any of the subsidiary tables, so that is first.
Second level is a distinct list of every kdsatker, akun in ANY of the other 3 tables. So now you can LEFT JOIN kdsatker thus keeping every record including 1, 2, 3 even though 2 & 3 have no records.
From the second level, you can now left-join to the tb_akun table which in this case, only kdsatker is the only one with records for any given akun.
Finally joining the pre-union list of all combinations grouped by kdsatker, akun are able to be matched for their final summary into the final list.
Hope each step makes sense to what you appear to be trying for.

mysql inner join condition to ignore duplicate ids

Given below the list of tables.
Order the shop ids in the descending order based on the sum of number of clicks for a product in the locations [23,24,25,26,27].
Given product_id = 8
link_shops_locations
shop_id | location_id
---------------------
1 | 23
2 | 24
3 | 25
3 | 26
3 | 27
products_clicks
shop_id | product_id | clicks
-----------------------------
1 | 8 | 1
2 | 7 | 3
2 | 8 | 87
3 | 8 | 21
3 | 8 | 9
link_products_shops
product_id | shop_id
---------------------
7 | 1
8 | 1
8 | 1
8 | 2
8 | 2
8 | 1
7 | 3
8 | 3
This is what I have tried,
SELECT SUM(c.clicks) as no,
s.shop_id
FROM link_products_shops l
INNER JOIN products_clicks c
ON c.product_id = l.product_id
INNER JOIN link_shops_locations s
ON s.shop_id = c.shop_id // duplicate shop_ids gives wrong SUM
WHERE s.location_id IN (23,24,25,26,27)
GROUP BY s.shop_id
ORDER BY no DESC;
My problem is, since the link_shops_locations table has 3 shop_ids, the resulting expected SUM is multiplied by 3. How do I solve this? The INNER JOIN condition of link_shops_locations has something to do with this?. A little help will be very useful.
[1]You missed one more condition in INNER JOIN with products_clicks.
[2]Also you ignored product_id. Have a look at this query.
[3]You had inserted product_id=8 and shop_id=1 three times in link_products_shops table.
select shop_id, SUM(NoOfClicks) FROM(SELECT distinct c.shop_id, c.clicks AS NoOfClicks
FROM products_clicks c
INNER JOIN link_products_shops l
ON c.product_id = l.product_id
AND c.shop_id = l.shop_id
INNER JOIN link_shops_locations s
ON s.shop_id = c.shop_id and s.shop_id = l.shop_id
WHERE s.location_id IN (23,24,25,26,27)
AND c.product_id = 8) AS TabShopCounters
GROUP BY shop_id
ORDER BY NoOfClicks DESC;
SQL Fiddle - http://www.sqlfiddle.com/#!2/b22fe/8

Filter query with order by and limit when using left join

How to filter query with order by and limit when using left join
store_profile
id + store_name
1 | Accessorize.me
2 | Active IT
3 | Edushop
4 | Gift2Kids
5 | Heavyarm
6 | Bamboo
store_fee
id + store_id + date_end
1 | 1 | 27-6-2013
2 | 2 | 29-8-2013
3 | 3 | 02-6-2013
4 | 4 | 20-4-2013
5 | 4 | 01-7-2013
6 | 4 | 28-9-2013
7 | 5 | 03-9-2013
8 | 6 | 01-9-2013
my previous query
$order_by_for_sort_column = "order by $column" //sorting column
$query = "SELECT * FROM store_profile sp LEFT JOIN store_fee sf ON (sf.store_id = sp.id) $order_by_for_sort_column";
what i want is order by id desc and limit 1 for table store_fee not for for entire query. So i can grab the latest date in date_end for each store.
As you can see for store_id 4(store_fee) i have 3 different date and i just want grab the latest date.
and the result should be something like this
1 | Accessorize.me 27-6-2013
2 | Active IT 29-8-2013
3 | Edushop 02-6-2013
4 | Gift2Kids 28-9-2013
5 | Heavyarm 03-9-2013
6 | Bamboo 01-9-2013
SELECT a.id, a.store_name, MAX(b.date_End) date_end
FROM store_profile a
LEFT JOIN store_fee b
ON a.ID = b.store_ID
GROUP BY a.id, a.store_name
SQLFiddle Demo
but if the datatype date_End column is varchar, the above query won't work because it sorts the value by character and that it can mistakenly gives undesired result. 18-1-2013 is greater than 01-6-2013.
To further gain more knowledge about joins, kindly visit the link below:
Visual Representation of SQL Joins
SELECT *
FROM store_profile AS sp
LEFT JOIN (
SELECT store_id, MAX(date_end)
FROM store_fee
GROUP BY store_id
) AS sf
ON sp.id=sf.store_id;

mysql join query

I have two tables that I need to join. These are:
art
id | art
--------
1 | A
2 | B
3 | C
4 | D
5 | E
6 | F
7 | G
8 | H
9 | I
and
Sess
artid | sessid
--------------
1 | 1
2 | 1
3 | 1
4 | 1
1 | 2
4 | 2
5 | 2
6 | 2
1 | 3
2 | 3
7 | 3
4 | 3
where Sess.artid is a foregin key to art.id.
From the tables above we can see that there are 3 sessions: A,B,C,D, A,D,E,F and A,B,G,D.
I want to get a ranking of the arts that occur along with art A. Something like:
D=3
B=2
How could I form such a query in mysql or postgres?
You need to join twice the session table to get the article sharing the same session.
Then join one time with article for the filter clause, and another time to get the name of the other article in the other session.
SELECT aSameSession.art, count(*)
FROM art a
INNER JOIN Sess s
ON a.id = s.artid
INNER JOIN Sess sSameArticle
ON sSameArticle.sessid = s.sessid
INNER JOIN art aSameSession
ON sSameArticle.artid = aSameSession.id
WHERE A.art = 'A'
AND aSameSession.art <> 'A'
GROUP BY aSameSession.art
Output :
B 2
C 1
D 3
E 1
F 1
G 1
This version could be a little difficult to understand, so here a version just with the ID of the article, which is much more simple :
SELECT sSameArticle.artid, count(*)
FROM Sess s
INNER JOIN Sess sSameArticle
ON sSameArticle.sessid = s.sessid
WHERE s.artid = 1
AND sSameArticle.artid != 1
GROUP BY sSameArticle.artid
Output :
2 2
3 1
4 3
5 1
6 1
7 1
Adding the name of the article is just cosmetic.
Something like this, perhaps:
select art,count(*)
from sessid
left join art on art.id=artid
where sessid in (select sessid from sess where artid=1)
group by artid;
?
Example of table structure and join queries on PostgreSQL
CREATE TABLE arts (
arts_id serial PRIMARY KEY,
name text NOT NULL
);
CREATE TABLE sessions (
sessions_id integer NOT NULL,
arts_id integer NOT NULL REFERENCES arts
);
SELECT arts.name, count(sessions_id)
FROM arts
JOIN sessions USING (arts_id)
GROUP BY arts.name
ORDER BY count(sessions_id) DESC;
SELECT a.art, count(*) as ranking
FROM art a, sess s
WHERE a.id = s.artid
group by a.art
order by count(*) DESC;
For a statement in ANSI-92 syntax have a look at Konerak's answer.

Finding the MIN value that appears for each unique value in either of two other columns

Given the following (simplified) tables:
People p
id name registered
-----------------------------------
1 Geoff 2011-03-29 12:09:08
2 Phil 2011-04-29 09:03:54
3 Tony 2011-05-29 21:22:23
4 Gary 2011-06-21 22:56:08
...
Items i
date p1id p2id
----------------------------------------
2011-06-29 20:09:44 1 2
2011-06-26 10:45:00 1 3
2011-06-23 12:22:43 2 3
2011-06-22 13:07:12 2 4
...
I'd like:
The earliest single i.date that each p.id appears in either column p1id or p2id; or p.registered if they feature in neither.
So far, I've tried:
CREATE TEMPORARY TABLE temp (id INT);
INSERT INTO temp (id)
SELECT DISTINCT u FROM (
SELECT p1id AS u FROM Items UNION ALL
SELECT p2id AS u FROM Items
)tt;
SELECT registered,id FROM People
WHERE id NOT IN (SELECT id FROM temp);
Which gets me as far as the second part, albeit in a fairly clumsy way; and I'm stuck on the first part beyond some sort of external, scripted iteration through all the values of p.id (ugh).
Can anyone help?
I'm on MySQL 5.1 and there's ~20k people and ~100k items.
One more solution:
SELECT id, name, IF(min_date1 IS NULL AND min_date2 IS NULL, registered, LEAST(COALESCE(min_date1, min_date2), COALESCE(min_date2, min_date1))) date FROM (
SELECT p.id, p.name, p.registered, MIN(i1.date) min_date1, MIN(i2.date) min_date2 FROM people p
LEFT JOIN items i1
ON p.id = i1.p1id
LEFT JOIN items i2
ON p.id = i2.p2id
GROUP BY id
) t;
OR this:
SELECT p.id, p.name, COALESCE(MIN(i.date), p.registered) FROM people p
LEFT JOIN (
SELECT p1id id, date FROM items
UNION ALL
SELECT p2id id, date FROM items
) i
ON p.id = i.id
GROUP BY id;
Result:
+------+-------+---------------------+
| id | name | date |
+------+-------+---------------------+
| 1 | Geoff | 2011-06-26 10:45:00 |
| 2 | Phil | 2011-06-22 13:07:12 |
| 3 | Tony | 2011-06-23 12:22:43 |
| 4 | Gary | 2011-06-22 13:07:12 |
+------+-------+---------------------+
This is tested in Postgres, but I think it ought to work in MySQL with few or no changes:
SELECT p.id,COALESCE(MIN(x.date),p.registered) AS date
FROM p
JOIN (
SELECT p.id,MIN(i.date) AS date
FROM p
JOIN i ON (p.id=i.p1id)
GROUP BY p.id
UNION
SELECT p.id,MIN(i.date) AS date
FROM p
JOIN i ON (p.id=i.p2id)
GROUP BY p.id
) AS x ON x.id = p.id
GROUP BY p.id,p.registered;
Output (given your sample data):
id | date
----+---------------------
3 | 2011-06-23 12:22:43
1 | 2011-06-26 10:45:00
2 | 2011-06-22 13:07:12
4 | 2011-06-22 13:07:12
(4 rows)