How to display a query in a certain way? - mysql

I'm currently new to queries and below I have a query that I have made
QUERY:
select TITLE_ID, TITLE,NAME, JOB_CATEGORY AS ROLE
FROM MOVIES
NATURAL JOIN NEW_NAMES
WHERE JOB_CATEGORY = 'writer'
OR JOB_CATEGORY = 'director'
ORDER BY TITLE_ID ASC;
Which Displays:
TITLE_ID | TITLE | NAME | ROLE |
753595 | 2F2F | ROB | WRITER |
753595 | 2F2F | YAS | DIRECTOR|
However I would like it to display in this format below:
TITLE_ID | TITLE | WRITER | DIRECTOR|
753595 | 2F2F | ROB | YAS |

You join your NEW_NAMES table in twice. Once for director, once for writer. When you join a table more than once it's necessary that you give the table an Alias, here we use writer and director.
select TITLE_ID, TITLE,writer.NAME as writer_name, director.NAME as director_name
FROM MOVIES
LEFT OUTER JOIN NEW_NAMES as writer
ON MOVIES.TITLE_ID = writer.TITLE_ID
AND writer.JOB_CATEGORY = 'writer'
LEFT OUTER JOIN NEW_NAMES as director
ON MOVIES.TITLE_ID = director.TITLE_ID
AND director.JOB_CATEGORY = 'director'
ORDER BY TITLE_ID ASC;
I've made some assumptions in those ON clauses about which columns in your tables you are joining on. You may need to edit that.

According to error message you got, it is about Oracle, not MySQL.
Anyway, such a (classic?) principle should work: aggregate!
SQL> with
2 -- sample data
3 movies (title_id, title_name) as
4 (select 753595, '2F2F' from dual union all
5 select 123456, '1Z1Z' from dual
6 ),
7 new_names (title_id, job_category, name) as
8 (select 753595, 'writer', 'ROB' from dual union all
9 select 753595, 'director', 'YAS' from dual
10 )
11 -- query you need
12 select m.title_id,
13 m.title_name,
14 max(case when n.job_category = 'writer' then n.name end) as writer,
15 max(case when n.job_category = 'director' then n.name end) as director
16 from movies m left join new_names n on m.title_id = n.title_id
17 group by m.title_id, m.title_name
18 order by m.title_id;
TITLE_ID TITL WRI DIR
---------- ---- --- ---
123456 1Z1Z
753595 2F2F ROB YAS
SQL>

Related

Find duplicates from same table and constraint them from another table in sql

Oh, my title is not the best one and as English is not my main language maybe someone can fix that instead of downvoting if they've understood the issue here.
Basically i have two tables - tourneyplayers and results. Tourneyplayers is like a side table which gathers together tournament information across multiple tables - results, tournaments, players etc. I want to check duplicates from the results table over column day1_best, from single tournament and return all the tourneyplayers who have duplicates.
Tourneyplayers contain rows:
Tourneyplayers
tp_id | resultid | tourneyid
1 | 2 | 91
2 | 21 | 91
3 | 29 | 91
4 | 1 | 91
5 | 3 | 92
Results contains rows:
Results:
r_id | day1_best
1 | 3
2 | 1
3 | 4
.. | ..
21 | 1
.. | ..
29 | 2
Now tourney with id = 91 has in total 4 results, with id's 1,2,21 and 29. I want to return values which have duplicates, so currently the result would be
Result
tp_id | resultid | day1_best
1 | 2 | 1
2 | 21 | 1
I tried writing something like this:
SELECT *
FROM tourneyplayers
WHERE resultid
IN (
SELECT r1.r_id
FROM results AS r1
INNER JOIN results AS r2 ON ( r1.day1_best = r2.day1_best )
AND (
r1.r_id <> r2.r_id
)
)
AND tourneyid =91
But in addition to values which had the same day1_best it chose two more which did not have the same. How could i improve my SQL or rewrite it?
First you JOIN both tables, so you know how the data looks like.
SELECT *
FROM tourney_players t
JOIN results r
ON t.`resultid` = r.`r_id`;
Then using the same query you GROUP to see what tourneyid, day1_best combination has multiple rows
SELECT `tourneyid`, `day1_best`, count(*) as total
FROM tourney_players t
JOIN results r
ON t.`resultid` = r.`r_id`
GROUP BY `tourneyid`, `day1_best`;
Finally you use the base JOIN and perform a LEFT JOIN to see what rows has a match and show only those rows.
SELECT t.`tp_id`, r.`r_id`, r.`day1_best`
FROM tourney_players t
JOIN results r
ON t.`resultid` = r.`r_id`
LEFT JOIN (SELECT `tourneyid`, `day1_best`, count(*) as total
FROM tourney_players t
JOIN results r
ON t.`resultid` = r.`r_id`
GROUP BY `tourneyid`, `day1_best`
HAVING count(*) > 1) as filter
ON t.`tourneyid` = filter.`tourneyid`
AND r.`day1_best` = filter.`day1_best`
WHERE filter.`tourneyid` IS NOT NULL;
SQL DEMO
OUTPUT
Please try this :
Select tp.tp_id , tp.resultid ,r.day1_best from (Select * from Tourneyplayers
where tourneyid = 91)as tp inner join (select * from Result day1_best in(select
day1_best from result group by day1_best having count(*)>1 ) )as r on tp.resultid
= r.r_id ;

PHP MySQL SELECT newest entry grouped by an ID and ordered by timestamp

I am working on an problem regarding Selecting data from two MySQL tables.
First table holds messages | messages | (id, msg_group_id, to_user_id, from_user_id, datetime)
Second table holds user data | profiles | (user_id, name, firstname, ...)
ATM it works the way, that I can select ALL messages with a certain 'to_id' and by adding a JOIN statement getting the name and firstname of the user who sends the message.
My problem now is that I can not figure out a way to ONLY select the newest message of a certain msg_group_id.
I already tried GROUP BY msg_group_id combined with ORDER BY datetime DESC.
But that only throws the very first entry in message table. But I want to last one. :-)
I hope you can help me. :-)
My actual SQL statement:
SELECT LEFT(messages.message, 10) AS message,
`messages`.`msg_group_id`,
`messages`.`datetime`,
`profiles`.`name`,
`profiles`.`firstname`
FROM `messages`
LEFT JOIN `profiles`
ON `messages`.`from_user_id` = `profiles`.`user_id`
WHERE `to_user_id` = '2'
ORDER BY `datetime` DESC
LIMIT 20;
Thanks in Advance
Sample INPUT:
[messages]
|id|msg_group_id|to_user_is|from_user_id|message |datetime|
0 | 1 | 1 | 2 | Hello World1 | 2015-12-21 10:42:00
1 | 1 | 1 | 2 | Hello World2 | 2015-12-21 10:43:00
2 | 1 | 1 | 2 | Hello World3 | 2015-12-21 10:44:00
[profiles]
user_id|name |firstname|
1 | Test | User
2 | Thanks | Worldname
Result (what I don't want)
message|msg_group_id|datetime|name|firstname
Hello World1 | 1 | 2015-12-21 10:42:00 | Thanks | Worldname
Result (what I want)
message|msg_group_id|datetime|name|firstname
Hello World3 | 1 | 2015-12-21 10:44:00 | Thanks | Worldname
May be this query can help:
SELECT m.message, m.msg_group_id, m.datetime, u.name, u.firstname
FROM message as m, profiles as u
WHERE m.from_user_id = u.user_id
GROUP BY m.msg_group_id
ORDER BY m.datetime DESC
Or use INNER JOIN
SELECT m.message, m.msg_group_id, m.datetime, u.name, u.firstname
FROM message as m
INNER JOIN profiles as u ON m.from_user_id = u.user_id
GROUP BY m.msg_group_id
ORDER BY m.datetime DESC
I guess I solved the Problem with the help of another thread:
https://stackoverflow.com/a/1313140/4493030
My SQL Statement as follows:
SELECT `messages`.*, `profiles`.`nick_name`
FROM `messages`
LEFT JOIN `profiles`
ON `messages`.`from_user_id` = `profiles`.`user_id`
INNER JOIN
(SELECT konversation_id, MAX(id) AS maxid FROM messages
WHERE messages.to_user_id = 2
GROUP BY konversation_id) AS b
ON messages.id = b.maxid
WHERE `to_user_id` = '2'
ORDER BY `datetime` DESC
LIMIT 20;
Thanks to all of you who tried to help.
I found a way to tight it down
SELECT messages.to_user_id, messages.msg_group_id, MAX(messages.id) AS maxid, messages.from_user_id, profiles.name
FROM messages
LEFT JOIN profiles
ON messages.from_user_id = profiles.user_id
WHERE messages.to_user_id = 2
GROUP BY msg_group_id

Select from one table but filtering other two

Let's say i've got this database:
book
| idBook | name |
|--------|----------|
| 1 |Book#1 |
category
| idCateg| category |
|--------|----------|
| 1 |Adventures|
| 2 |Science F.|
book_categ
| id | idBook | idCateg | DATA |
|--------|--------|----------|--------|
| 1 | 1 | 1 | (null) |
| 2 | 1 | 2 | (null) |
I'm trying to select only the books which are in category 1 AND category 2 something like this
SELECT book.* FROM book,book_categ
WHERE book_categ.idCateg = 1 AND book_categ.idCateg = 2
Obviously, this giving 0 results becouse each row has only one idCateg it does work width OR but the results are not what I need. I've also tried to use a join, but I just can't get the results I expect.
Here it's the SQLFiddle of my current project, with my current DB, the data at the begining is just a sample. SQLFiddle
Any help will be really appreciated.
Solution using EXISTS:
select *
from book b
where exists (select 'x'
from book_categ x
where x.idbook = b.idbook
and x.idcateg = 1)
and exists (select 'x'
from book_categ x
where x.idbook = b.idbook
and x.idcateg = 2)
Solution using join with an inline view:
select *
from book b
join (select idbook
from book_categ
where idcateg in (1, 2)
group by idbook
having count(*) = 2) x
on b.idbook = x.idbook
You could try using ALL instead of IN (if you only want values that match all criteria to be returned):
SELECT book.*
FROM book, book_categ
WHERE book_categ.idCateg = ALL(1 , 2)
One way to get the result is to do join to the book_categ table twice, something like
SELECT b.*
FROM book b
JOIN book_categ c1
ON c1.book_id = b.id
AND c1.idCateg = 1
JOIN book_categ c2
ON c2.book_id = b.id
AND c2.idCateg = 2
This assumes that (book_id, idCateg) is constrained to be unique in the book_categ table. If it isn't unique, then this query can return duplicate rows. Adding a GROUP BY clause or the DISTINCT keyword will eliminate any generated duplicates.
There are several other queries that can get generate the same result.
For example, another approach to finding book_id that are in two categories is to get all the rows with idCateg values of 1 or 2, and then GROUP BY book_id and get a count of DISTINCT values...
SELECT b.*
FROM book b
JOIN ( SELECT d.book_id
FROM book_categ d
WHERE d.idCateg IN (1,2)
GROUP BY d.book_id
HAVING COUNT(DISTINCT d.idCateg) = 2
) c
ON c.book_id = b.id

Inner join with where

I need to get Max bid and that username but result is coming in wrong way
Here is my two tables
Product
id | name | username
1 | A | deen
2 B | ann
Bid
id | c_bid | username
1 | 10 | ann
1 | 12 | ann
1 | 13 | ann
2 | 10 | ann
1 | 15 | Hel
1 | 16 | Hel
SQL
SELECT name, bid.username AS username, MAX(bid.c_bid) AS c_bid FROM product INNER JOIN bid
ON gems.id= bidding.id WHERE bid.id = '1'
Result
name | c_bid | username
A | 16 | ann
Why is this result coming on this sql?
Since you are using an aggregate function you need to include a GROUP BY.
SELECT name,
bid.username AS username,
MAX(bid.c_bid) AS c_bid
FROM product
INNER JOIN bid
ON product.id= bid.id
WHERE bid.id = '1'
GROUP BY name, bid.username
See SQL Fiddle with Demo
You are getting strange results because MySQL uses an Extension to GROUP BY that allows you to use an aggregate function without using a GROUP BY but this could cause your result to be incorrect.
The GROUP BY makes it so you will return the max(bid) for each item that you are grouping by, in your case it is name and `username.
If you want to return only one max(bid) for each product id, then you could use:
SELECT name,
bid.username AS username,
bid.c_bid
FROM product
INNER JOIN bid
ON product.id= bid.id
INNER JOIN
(
SELECT max(c_bid) c_bid, id
FROM bid
GROUP BY id
) b
on bid.id = b.id
and bid.c_bid = b.c_bid
WHERE bid.id = '1'
See SQL Fiddle with Demo
Use GROUP BY.
SELECT name, bid.username AS username, MAX(bid.c_bid) AS c_bid FROM product INNER JOIN bid
ON gems.id= bidding.id WHERE bid.id = '1' GROUP BY bid.username;
SELECT
p.username,
MAX(b.c_bid) AS max_c_bid
FROM product p
LEFT JOIN bid b ON (p.username = b.username)
GROUP BY p.username;
SELECT
pr.name,
mb.c_bid,
pr.username
FROM
(
SELECT
SUBSTRING_INDEX(GROUP_CONCAT(id ORDER BY c_bid DESC), ',', 1) AS id,
MAX(c_bid) AS c_bid
FROM bid
GROUP BY id
) AS mb
JOIN product AS pr ON(pr.id = mb.id)
Example: http://sqlfiddle.com/#!2/0a6c9/2

difficulties getting a 3 table join to return expected results

I'm having some difficulty getting to the bottom of this sql query.
Tables:
--Tickets-- --Finance-- --Access--
id_tickets id_finance id_access
name_tickets id_event id_event
cat_tickets id_tickets id_tickets
sold_finance scan_access
Finance and Access both contain a row for multiple of each ticket type as listed in tickets.
and I'm trying to get:
cat_tickets | total_sold | total_scan
-------------------------------------
single | 3043 | 2571
season | 481 | 292
comp | 114 | 75
-------------------------------------
total | 3638 | 2938
The closest I've been to the result I've used:
SELECT tickets.cat_tickets, COALESCE(SUM(finance.sold_finance), 0) AS total_sold, COALESCE(SUM(access.scan_access), 0) AS total_scan
FROM finance INNER JOIN tickets ON finance.id_tickets = tickets.id_tickets
INNER JOIN access ON access.id_tickets = tickets.id_tickets
WHERE access.id_event = 235 AND finance.id_event = access.id_event
GROUP BY tickets.cat_tickets
ORDER BY tickets.cat_tickets DESC
but that just returns:
cat_tickets | total_sold | total_scan
-------------------------------------
single | 4945 | 4437
season | 954 | 599
comp | 342 | 375
-------------------------------------
total | 6241 | 5411
Any ideas where I could be going wrong?
Thanks!
The problem is the relation between access and finance tables, you have to join them. Even if you LEFT JOIN the table the predicate finance.id_event = access.id_event will make it INNER JOIN. As a work around, use UNION like this:
SELECT
tickets.cat_tickets,
SUM(CASE WHEN a.Type = 'f' THEN num ELSE 0 END) AS total_sold,
SUM(CASE WHEN a.Type = 'a' THEN num ELSE 0 END) AS total_scan
FROM tickets
LEFT JOIN
(
SELECT 'f' Type, id_tickets, sold_finance num
FROM finance f
WHERE id_event = 1
UNION ALL
SELECT 'a', id_tickets, scan_access
FROM access
WHERE id_event = 1
) a ON a.id_tickets = tickets.id_tickets
GROUP BY tickets.cat_tickets;
SQL Fiddle Demo
Although I am fully clear on what you want, just try this query if the result of this is what you are expecting.
SELECT tickets.cat_tickets, COALESCE(SUM(finance.sold_finance), 0) AS total_sold, COALESCE(SUM(access.scan_access), 0) AS total_scan
FROM finance LEFT JOIN tickets ON finance.id_tickets = tickets.id_tickets
LEFT JOIN access ON access.id_tickets = tickets.id_tickets
WHERE access.id_event = 235
GROUP BY tickets.cat_tickets
ORDER BY tickets.cat_tickets DESC
Disclaimer: This query is not tested due to incomplete data on the question.
SELECT z.Cat_tickets,
COALESCE(x.total_sold,0) total_sold,
COALESCE(y.total_scan,0) total_scan
FROM tickets z
LEFT JOIN
(
SELECT a.id_tickets,
a.cat_tickets,
SUM(b.sold_finance) total_sold
FROM tickets a
INNER JOIN finance b
ON a.id_tickets = b.id_tickets
WHERE id_event = 235
GROUP BY a.id_tickets, a.cat_tickets
) x ON z.id_tickets = x.id_tickets
LEFT JOIN
(
SELECT aa.id_tickets,
aa.cat_tickets,
SUM(bb.scan_access) total_scan
FROM tickets aa
INNER JOIN Access bb
ON aa.id_tickets = bb.id_tickets
WHERE id_event = 235
GROUP BY aa.id_tickets, aa.cat_tickets
) y ON z.id_tickets = y.id_tickets