I want to plan my trips publicly so other people can join me. So, I have set-up an PHP site.
I have this tables:
trips:
+----+---------+------------+------------+-------------------------+
| id | title | date_start | date_end | marker_adress |
+----+---------+------------+------------+-------------------------+
| 1 | Berlin | 2015-07-10 | 2015-07-11 | Potsdamer Platz, Berlin |
| 2 | Hamburg | 2015-07-16 | 2015-07-18 | Jungfernstieg, Hamburg |
+----+---------+------------+------------+-------------------------+
fellows:
+----+---------+---------------+
| id | trip_id | twittername |
+----+---------+---------------+
| 1 | 1 | prtyengopls |
| 2 | 1 | itobi_yt |
| 3 | 1 | jessisadancer |
| 4 | 2 | jessisadancer |
| 5 | 2 | woelfch3n |
+----+---------+---------------+
For displaying sake, I want to query them in one query. How can I query the database so I have something like this? (I know, it's JSON but it shows the structure very well.)
{
"id": 1,
"date_start": "2015-07-10",
"date_end": "2015-07-11",
"marker_adress": "Potsdamer Platz, Berlin",
"fellows": [
{
"id": 1,
"twittername": "prtyengopls"
},
{
"id": 2,
"twittername": "itobi_yt"
},
{
"id": 3,
"twittername": "jessisadancer"
}
]
}
First you have to use a LEFT JOIN like this:
SELECT
t.id AS tripID,
t.title AS title,
t.date_start AS dateStart,
t.date_end AS dateEnd,
t.marker_address AS markerAddress,
GROUP_CONCAT(DISTINCT CAST(f.id AS CHAR)) AS fellowID,
GROUP_CONCAT(DISTINCT CAST(f.twittername AS CHAR)) AS twitterName
FROM trips t LEFT JOIN fellows f ON t.id = f.trip_id
GROUP BY t.id
By using this you will get a single row for each trip and you can loop over fellowID and twitterName for each row, as it will be comma delimited list like this:
fellowID: 1,2,3
twitterName: prtyengopls,itobi_yt,jessisadancer
Edit 1: I got a new column to trips called checked which is a boolean.
Could you update your query, so only trips that have this boolean
toggled on are displayed?
SELECT
t.id AS tripID,
t.title AS title,
t.date_start AS dateStart,
t.date_end AS dateEnd,
t.marker_address AS markerAddress,
GROUP_CONCAT(DISTINCT CAST(f.id AS CHAR)) AS fellowID,
GROUP_CONCAT(DISTINCT CAST(f.twittername AS CHAR)) AS twitterName
FROM trips t INNER JOIN fellows f
ON t.id = f.trip_id AND t.checked = 1
GROUP BY t.id
I don't think it's possible like you expected in SQL. Just to answer your question and show you the problem: you have to use a join (left, inner or something ... depends of your database structure; I always prefer left joins if possible) to get all information in just one query:
SELECT * FROM trips t LEFT JOIN fellows f on t.id = f.trip_id WHERE t.id = 1;
But you always will get the trip information with every row, and for that you have to process it afterwards. You will never able to select such a nested structure, you will always get a flat one.
So I would recommend to split it into two queries like this:
SELECT * FROM trips WHERE id = 1;
SELECT * FROM fellows WHERE trip_id = 1;
You will have to process the information afterwards too, but you just select the wanted information from your database.
Hope that helps.
Related
Im not very familiar with using 'join' in queries. I really tried solving this by my own, but it seems to be too hard.
I got 2 Tables:
Table 'users':
+-----------------+-----------------+
| member | online |
+-----------------+-----------------+
| mahran | 1 |
| peter | 1 |
| Jen | 1 |
| Steve | 0 |
+-----------------+-----------------+
Table 'tickets'
+-----------------+----------------+----------------+
| name | category | time |
+-----------------+----------------+----------------+
| mahran | silver | 1 |
| peter | blue | 1 |
| mahran | blue | 2 |
| peter | red | 3 |
| peter | green | 2 |
| Jen | silver | 1 |
+-----------------+----------------+----------------+
The chellange:
I need each member (users.member) who's online (users.online). The next thing is to get the category for each member (user.member = tickets.name) with the highest time (probably ORDER BY time DESC LIMIT 1).
So, for example:
Peter is online. Peters highest time is 3 at the position of category=red. So I want peter to show up in the result with his category 'red'. Mahran would show up with blue. Jen would get silver. And steve would be left out because he's not online.
I hope this was clear. In general I know how the queries would look like but theres no chance for me merging them together.
What needs to be merged:
SELECT member FROM users WHERE online = 1;
|
v for each member
SELECT category FROM tickets WHERE name=users.member ORDER BY time DESC.
So, any ideas how to solve this?
Here is a fiddle with a not working query: Click
You can do this easily with a correlated subquery:
select u.member,
(select t.category
from tickets t
where t.name = u.member
order by t.time desc
limit 1
) as MostRecentCategory
from users u
where u.online = 1;
This can make use of the following indexes: users(online, member) and ticket(member, time, category).
Here is the query you're looking for:
SELECT U.member
,T.category
FROM users U
INNER JOIN tickets T ON T.name = U.member
INNER JOIN (SELECT T2.name
,MAX(T2.time) AS [maxTime]
FROM tickets T2
GROUP BY T2.name) AS M ON M.name = T.name
AND M.maxTime = T.time
WHERE U.online = 1
The use of [name] to join the two tables is not a good practice, it's much better to use keys instead. But my query is just here to help you understanding the process of jointure.
Hope this will help you.
If i understand you correctly
SELECT DISTINCT users.member, tickets.category FROM tickets JOIN users ON users.member = tickets.name WHERE users.online = 1 ORDER BY tickets.time DESC
Can you make sql fiddle?
USE DISTINCT
stackoverflow.com/questions/11704012/mysql-distinct-join
try this
SELECT DISTINCT User.member,Ticket.category FROM users AS USER
INNER JOIN tickets AS Ticket ON (User.member = Ticket.name)
WHERE User.online = 1;
Sorry, but peter seems to be RED, It's time is 3. Don't you?
Depending on table definition, is not guaranteed to have one only result for each user.
For example, if peter has time 3 in two categories, you can get one different category depending of the SQL sorting method.
To be sure, tickets.Category and tickets.time must be in a unique key (both toghether, not a unike key for each field)
Assuming that, the Query could be this.
select t2.name, t2.category
from
tickets t2
INNER JOIN (Select
u.member, max(time)
from users u, tickets t
where
u.member = t.name
and u.online = 1
group by u.member
) as usermaxtime on t2.name = usermaxtime.member;
I'm making a search function in PHP and I have three tables that I wish to join to a single one; the three tables looks as follow:
band
ID | bands
---+----------
1 | Muse
2 | Coldplay
3 | etc.
release
ID | releases
---+----------
1 | Showbiz
2 | Origin of Symmentry
3 | etc.
track
ID | tracks
---+-----------
1 | Sunburn
2 | Muscle Museum
3 | etc.
I want these tables to be put into this:
discografic
ID | band_id | release_id | track_id
---+----------+-------------+---------
1 | 1 | 1 | 1
2 | 1 | 1 | 2
3 | etc.
So that the table with the SQL code looks like this:
discografic
ID | bands | releases | tracks
---+----------+-------------+---------
1 | Muse | Showbiz | Sunburn
2 | Muse | Showbiz | Muscle Museum
3 | etc.
I want to INNER JOIN these tables. I joined one but I can't really figure out how the get the last joined as well.
SELECT *
FROM band
INNER JOIN discografic
ON band.id = discografic.band_id
This should probably have its own question; I also want to be able to search this database, but only have the result show up once, and also reference to the band every time. For example, if I search "Showbiz" it will give me "Muse", and only show it once.
Note: This is for testing purposes only, security is none of my concerns.
Try with this query:
select d.id,b.bands,r.releases,t.tracks from discografic as d INNER JOIN band as b on
d.band_id=b.id INNER JOIN release as r on d.release_id=r.id INNER JOIN track as t on
d.track_id=t.id GROUP BY d.id
Try This query
Select a.ID,b.bands,c.releases,d.tracks from discografic as a
inner join band as b on a.band_id = b.ID
inner join release as c on a.release_id = c.ID
inner join track as d on a.track_id = d.ID
where b.bands = 'Muse'
Use this query to insert the data like you wanted:
Insert into discograpy
(id,bands,releases,tracks)
SELECT band.ID,bands,releases,tracks
FROM band
INNER JOIN releases
ON band.id = releases.id
inner join track
on band.id = track.id
Use this query to show you only one band:
Declare #releases varchar(50)
Set #releases = 'showbiz'
SElect distinct bands from discograpy where releases = #releases
Here any variable can be passed or set in place of showbiz. This is an example
I'd like to ask you for help with a query (mysql). I have 3 tables:
1.table "reviews"
ID | content |
--------------------------------------
1 | content of first review
2 | content of second review
2.table "pros"
ID | reviews_ID | pros |
---------------------------------------
1 | 1 | good service |
2 | 1 | nice look |
3 | 1 | not bad price|
4 | 2 | good service |
5 | 2 | design |
3.table "cons"
ID | reviews_ID | pros |
---------------------------------------
1 | 1 | delays |
4 | 2 | mistakes |
5 | 2 | troubles |
What I am trying to do is merge informations from these 3 tables, where "reviews" table is the main one and table 2, 3 are pointing to it (reviews_ID).
I'd like to get results like this:
=> content of first review
+ good service - delays
+ nice look
+ not bad price
of course in array/result, this is just for better understand :)
try this sqlFiddle
with GROUP_CONCAT you can explode pros and cons into an array or whatever in php.
SELECT content,p.pros,c.cons
FROM reviews
LEFT JOIN
(SELECT reviews_id,GROUP_CONCAT(pros)as pros
FROM pros
GROUP BY reviews_id)as p
ON p.reviews_id = reviews.id
LEFT JOIN
(SELECT reviews_id,GROUP_CONCAT(cons)as cons
FROM cons
GROUP BY reviews_id)as c
ON c.reviews_id = reviews.id
WHERE reviews.id = 1;
result will be
CONTENT PROS CONS
content of first review good service,nice look,not bad service delays
SELECT statement produces only two-dimensional table. so, you could not obtain hierarchical tree using STANDARD SELECT. I suggest following SQL and convert display format in client side.
SELECT 'content',r.content as value
FROM reviews r
WHERE r.ID = 1
UNION
SELECT 'pros', p.pros
FROM reviews r LEFT JOIN pros p
ON r.ID = p.reviews_ID
WHERE r.ID = 1
UNION
SELECT 'cons', c.cons
FROM reviews r LEFT JOIN cons c
ON r.ID = c.reviews_ID
WHERE r.ID = 1
Try this:
SELECT A.content, B.pros, C.cons
FROM reviews A LEFT JOIN pros B ON A.ID = B.reviews_ID
LEFT JOIN cons C ON A.ID = C.reviews_ID
I actually have these tables :
- Table games -
ID
Name
- Table ean -
ID
ID_games
EAN
And I have this request :
SELECT games.*, ean.EAN
FROM games
LEFT JOIN ean ON (games.ID = ean.ID_games)
The result will be something like this :
| 1 | Half Life | 358958595 |
| 1 | Half Life | 589584859 |
| 2 | Half Life 2 | 385953684 |
| 2 | Half Life 2 | 585100335 |
etc.
When I do my request and use it in php, it is not useful to have a lot of line with about the same results. I would like to do something like this :
SELECT games.*, ConvertToArray(ean) AS ean_array
FROM games
LEFT JOIN ean ON (games.ID = ean.ID_games)
And have results like this :
| 1 | Half Life | (358958595,589584859) |
| 2 | Half Life 2 | (385953684,585100335 ) |
etc.
Is it possible to that with mysql ? Without an UDF ? And with an UDF ?
Thank you,
Kevin
Do you object to using GROUP_CONCAT? This would give you a nice delimited list (Assuming the ean value will never have your delimiter within):
SELECT games.*, GROUP_CONCAT(ean.EAN) AS ean_list,
FROM games
LEFT JOIN ean
ON games.ID = ean.ID_games
GROUP BY games.ID, games.name
Resulting in:
| 1 | Half Life | 358958595,589584859 |
| 2 | Half Life 2 | 385953684,585100335 |
Also, here's a qeustion I found with this logic applied: mySql - creating a join using a list of comma separated values
See GROUP_CONCAT().
Example can be found here.
Your query would look something like:
SELECT games.*, GROUP_CONCAT(DISTINCT ean) AS ean_array
FROM games
LEFT JOIN ean ON (games.ID = ean.ID_games)
GROUP BY games.ID
Try this one:
SELECT g.id, GROUP_CONCAT(CAST(e.ean AS CHAR) SEPARATOR ', ')
FROM games g
LEFT JOIN ean e ON g.id = e.id_games
GROUP BY g.id;
I'm creating a site in wordpress which holds information on television programs. I'm using custom fields to select each post.
The table looks something like this
+----+---------+----------+------------+
| id | post_id | meta_key | meta_value |
+----+---------+----------+------------+
| 1 | 1 | name | Smallville |
| 2 | 1 | season | 1 |
| 3 | 1 | episode | 1 |
| 4 | 2 | name | Smallville |
| 5 | 2 | season | 1 |
| 6 | 2 | episode | 2 |
+----+---------+----------+------------+
Basically what I need to do is select all of the tv shows with the name "Smallville" and sort them by season then by episodes. I thought it would be fairly simple but everything I have tried returns nothing.
Could you please explain how I can do this?
You can do something like this:
SELECT
t1.post_id,
t1.meta_value AS name,
t2.meta_value AS season,
t3.meta_value AS episode
FROM
(
SELECT *
FROM the_table
WHERE meta_key = 'name'
) t1
INNER JOIN
(
SELECT *
FROM the_table
WHERE meta_key = 'season'
) t2 ON t1.post_id = t2.post_id
INNER JOIN
(
SELECT *
FROM the_table
WHERE meta_key = 'episode'
) t3 ON t1.post_id = t3.post_id
This will give you the result:
| post_id | name | season | episode |
-------------------------------------------
| 1 | Smallville | 1 | 1 |
| 2 | Smallville | 1 | 2 |
In this form it is much easier for any operations.
What you need is to add:
WHERE name = 'Smallville'
ORDER BY season, episode
Combine the rows using a self-join, and you're good to go:
SELECT *
FROM yourtable name
INNER JOIN yourtable season
on season.post_id = name.post_id
and season.meta_key = 'season'
INNER JOIN yourtable episode
on episode.post_id = name.post_id
and episode.meta_key = 'episode'
WHERE name.meta_key = 'name'
and name.meta_value = 'Smallville'
ORDER BY season.meta_value, episode.meta_value
A more general case: sort-of conversion from your format to a more normal relational DB format:
SELECT (SELECT meta_value FROM data t1 WHERE t1.post_id = t0.post_id AND meta_key = "season") AS season,
(SELECT meta_value FROM data t1 WHERE t1.post_id = t0.post_id AND meta_key = "episode") AS episode
FROM data t0 WHERE meta_key = "name" AND meta_value = "Smallville"
For the actual sorting you can't reuse the season / episode values (those aren't assigned yet while sorting), so you have to copy/paste the subquery into the ORDER BY clause:
ORDER BY (SELECT ... "season") ASC, (SELECT ... "episode") ASC,
No need to do direct SQL.
You've got access to the SQL query through the WP_Query object. Check out the filters surrounding the where clause in the WP_Query object (there is more than 1 way to get at it) and simply modify the default WP_Query parts before they're concatenated together.
Start by setting up a WP_Query object that gets all the posts by postmeta key & postmeta value, and then tack on a bit more to the where clause to do some extra conditionals.
There's another filter that allows you to get at the ordering section of the SQL query so you can modify that.
There's no reason to hand write SQL here, just modify what has already been built for you.
the idea is to join the table to itself 3 times where for each of them take rows for a given meta_key:
SELECT t1.meta_value name, t2.meta_value season, t3.meta_value episode
FROM table t1
JOIN table t2 on t1.post_id = t2.post_id and t2.meta_key = 'season'
JOIN table t3 on t1.post_id = t3.post_id and t3.meta_key = 'episode'
WHERE t1.meta_key = 'name'
AND t1.meta_value = 'Smallville'
ORDER BY t2.meta_value, t3.meta_value