So far I haven't been successful in my search on combining 4 tables. I have 4 tables:
content
content_id | source_id | content_title | content_date
--------------------------------------------------------
1 | 1 | The factory | 189982398300
2 | 2 | Cold and cloudy | 189982398299
3 | 2 | Green tea | 189982398298
sources
source_id | source_name
-------------------
1 | BBC
2 | Reuters
settings
setting_id | setting_name
-------------------------------
1 | bbc_iplayer_string
2 | reuters_video_id
3 | reuters_category
content_join_settings
content_id | setting_id | setting_data
------------------------------------------
1 | 1 | Js88sdhjsd0gDS09
2 | 2 | video_8AJK3ADJD8
2 | 3 | weather
3 | 2 | video_K7KD8N2ND9
3 | 3 | food and drinks
So as you might have already noticed every content record has it's own source linked to it, and comes with extra settings depending on the source. BBC posts have an bbc_iplayer_string, and posts from Reuters have a reuters_video_id and a reuters_category. Of course this is just an example.
I'd like to have the results combined, and with the setting_name as a column name. I'm not sure how to explain it so I'll show it:
content_id | source_name | content_title | content_date | bbc_iplayer_string | reuters_video_id | reuters_category
--------------------------------------------------------------------------------------------------------
1 | BBC | The factory | 189982398300 | Js88sdhjsd0gDS09 | NULL | NULL
2 | Reuters | Cold and cloudy | 189982398299 | NULL | video_8AJK3ADJD8 | weather
3 | Reuters | Green tea | 189982398298 | NULL | video_K7KD8N2ND9 | food and drinks
I'm not very skilled in complex MySQL queries. I don't know where to start looking, let alone what to search for. I started with this query but I have no idea how to continue. I'm probably not even close.
SELECT
*
FROM
content,
sources,
settings,
content_join_settings
WHERE
content.content_id = content_join_settings.content_id AND
settings.setting_id = content_join_settings.setting_id AND
sources.source_id = content.source_id
GROUP BY
content.content_id
ORDER BY
content.content_date
DESC
You need to join the tables, and then pivot the results to move rows into columns.
SELECT c.content_id, s.source_name, c.content_title, c.content_date,
MAX(CASE setting_name WHEN 'bbc_iplayer_string' THEN setting_data END) AS bbc_iplayer_string,
MAX(CASE setting_name WHEN 'reuters_video_id' THEN setting_data END) AS reuters_video_id,
MAX(CASE setting_name WHEN 'reuters_category' THEN setting_data END) AS reuters_category
FROM content AS c
INNER JOIN sources AS s ON s.source_id = c.source_id
INNER JOIN content_join_settings AS cjs ON cjs.content_id = c.content_id
INNER JOIN settings as st ON st.setting_id = cjs.setting_id
GROUP BY c.content_id
DEMO
Would this help ?
SELECT
*
FROM
content as ct inner join sources as ss on ct.source_id = ss.source_id
inner join content_join_settings as cst on ct.setting_id = cst.setting_id
inner join settings as st on st.setting_id = cst.setting_id
GROUP BY
content.content_id
ORDER BY
content.content_date
DESC
Related
I'm trying to setup a new permissions database in MySQL and I'm breaking my brain over something that I'm sure is very simple. I'm certain something to this tune has been answered here before but after hours of searching I have found nothing that works.
I have 4 tables that are relevant
Permission (contains every possible permission)
|permission_name | description |
--------------------------------
|users.list | etc. etc. |
|users.update | etc. etc. |
|users.delete | etc. etc. |
User
| id | fname | group_id |
------------------------------
| 1 | John | 1 |
| 2 | Nancy | 1 |
| 3 | Paul | 2 |
Group
| group_id | group_name |
-------------------------
| 1 | Webmasters |
| 2 | Corporate |
| 3 | HR |
Group_permission (contains permissions relevant to each group)
| group_id | permission_name | permission_type (1=Y|0=not set|-1=N)
----------------------------------------------
| 1 | users.list | 1 |
| 1 | users.update | 1 |
| 2 | users.list | 1 |
OK so lots of relations going on, but I'm trying to get ALL the group permissions for a specific user EVEN if the group permission doesn't exist yet.
I imagined this being some sort of left join using a permission table as a base, but whenever I include the WHERE user.id = 2 it limits my result set down and won't include nulls on the right side.
SELECT a.permission_name, IFNULL(b.permission_type, 0)
FROM permission a
LEFT JOIN group_permission b on b.permission_name = a.permission_name
LEFT JOIN user c on c.group_id = b.group_id
WHERE c.id = 2
the result I want to see for Nancy is
|permission_name | permission_type |
------------------------------------
|users.list | 1 |
|users.update | 0 |
|users.delete | 0 |
I won't know what group the user is in on the PHP side, so I have to query by using the users ID only.
All I'm getting is
|permission_name | permission_type |
------------------------------------
|users.list | 1 |
Any help appreciated. TIA
It ended up being just a subquery that did the trick.
SELECT a.permission_name, IFNULL(b.permission_type, 0)
FROM permission a
NATURAL LEFT JOIN
(
SELECT a.group_id, a.permission_name, a.permission_type FROM group_permission a
NATURAL LEFT JOIN users b
WHERE b.id = 2
) as b
Not 100% sure that this will work, but try joining the group_permissions table to the permissions table.
SELECT a.permission_name, IFNULL(b.permission_type, 0)
FROM group_permission a
LEFT JOIN permission b on a.permission_name = b.permission_name
LEFT JOIN user c on c.group_id = b.group_id
WHERE c.id = 2
It's the 3rd day I'm trying to write a MySQL query. Did lots of search, but it still doesn't work as expected. I'll try to simplify tables as much as possible
System has tkr_restaurants table:
restaurant_id | restaurant_name
1 | AA
2 | BB
3 | CC
Each restaurant has a division assigned (tkr_divisions table):
division_id | restaurant_id | division_name
1 | 1 | AA-1
2 | 1 | AA-2
3 | 2 | BB-1
Then there are meals in tkr_meals_to_restaurants_divisions table, where each meal can be assigned (mapped) to whole restaurant(s) and/or specific division(s). If meal is mapped to restaurant, all restaurant's divisions should see it. If meal is mapped to division(s), only specific division(s) should see it.
meal_id | mapped_restaurant_id | mapped_division_id
1 | 1 | NULL
2 | NULL | 1
3 | NULL | 2
I need to display a list of restaurants and number of meals mapped to it depending on user permissions.
Example 1: if user has permissions to access whole restaurant_id 1 and restaurant_3 (and no specific divisions), then list should be:
AA | 3
CC | 0
(because user can access meals mapped to restaurant 1 + all its division, and restaurant 3 + all its divisions (even if restaurant 3 has no divisions/meals mapped))
Example 2: if user has permissions to access only division_id 1, then list should be:
AA | 1
(because user can only access meals mapped to division 1).
The closest query I could get is:
Example 1:
SELECT *,
(SELECT COUNT(DISTINCT meal_id)
FROM
tkr_meals_to_restaurants_divisions
WHERE
tkr_meals_to_restaurants_divisions.mapped_restaurant_id=tkr_restaurants.restaurant_id
OR tkr_meals_to_restaurants_divisions.mapped_division_id=tkr_divisions.division_id)AS total_meals
FROM
tkr_restaurants
LEFT JOIN
tkr_divisions
ON tkr_restaurants.restaurant_id=tkr_divisions.restaurant_id
WHERE
tkr_restaurants.restaurant_id IN (1, 3)
OR tkr_restaurants.restaurant_id IN (
SELECT restaurant_id
FROM tkr_divisions
WHERE division_id IN (NULL)
)
GROUP BY
tkr_restaurants.restaurant_id
ORDER BY
tkr_restaurants.restaurant_name
However, result was:
AA | 2
CC | 0
I believe I'm greatly over-complicating this query, but all the simpler queries I wrote produced even more inaccurate results.
What about this query:
SELECT
FROM tkr_restaurants AS a
JOIN tkr_divisions AS b
ON a.restaurant_id = b.restaurant_id
LEFT OUTER JOIN tkr_meals_to_restaurants_divisions AS c
ON (c.mapped_restaurant_id = a.restaurant_id OR c.mapped_division_id = b.division_id)
As a Base four your further work. It combine all information into one table. If you add e.g. this:
WHERE a.restaurant_id IN (1, 3)
the result will be
| restaurant_id | restaurant_name | division_id | restaurant_id | division_name | meal_id | mapped_restaurant_id | mapped_division_id |
|---------------|-----------------|-------------|---------------|---------------|---------|----------------------|--------------------|
| 1 | AA | 1 | 1 | AA-1 | 1 | 1 | (null) |
| 1 | AA | 2 | 1 | AA-2 | 1 | 1 | (null) |
| 1 | AA | 1 | 1 | AA-1 | 2 | (null) | 1 |
| 1 | AA | 2 | 1 | AA-2 | 3 | (null) | 2 |
just count the distinct meal ids with COUNT(DISTINCT c.meal_id) and take the restaurant name to get AA: 3 for your example 2
I used a sqlfiddle: http://sqlfiddle.com/#!9/fa2b78/18/0
[EDIT]
Change JOIN tkr_divisions AS b to LEFT OUTER JOIN tkr_divisions AS b
Change SELECT * to SELECT a.restaurant_name, COUNT(DISTINCT c.meal_id)
Add a GROUP BY a.restaurant_name at the end.
Update the SQL Fiddle (new link)
I have this query, it joins two tables and give me results of all the data under one a condition CATID is
'videography'
SELECT
pm_categories_images.Image,
pm_categories_images.FileURL,
pm_categories.catname,
pm_categories.`status`,
pm_categories.sortorder,
pm_categories.parentID,
pm_categories_images.CatID
FROM
pm_categories
LEFT JOIN pm_categories_images ON pm_categories_images.CatID = pm_categories.catID
where pm_categories_images.CatID IN (select catid from pm_categories where
parentID = (select catID from pm_categories where catname = 'Videography'))
Now this videography has a results like this
http://prntscr.com/gpkuyl
now i want to get 1 record for every catname
Without a MCVE and actual requirements on which image you want from the images table and a better understanding of why you need a left join when your where clause makes it behave like an inner... and why the where clause is so complex... ...I'm really unsure what the question is after... Here's a shot... and a DEMO:http://rextester.com/CRBN50943
Sample data expected results always a plus: I made my own and several assumptions
I interperted the question as: I would like a list of the categories along with a image having the earliest alphabetic value for each category.
SELECT
CI.Image,
CI.FileURL,
C.catname,
C.`status`,
C.sortorder,
C.parentID,
CI.CatID
FROM pm_categories C
INNER JOIN pm_categories_images CI
ON CI.CatID = C.catID
INNER JOIN (SELECT Min(Image) MI, catID FROM pm_categories_images group by CATID) Z
on CI.Image = Z.MI
and CI.CatID = Z.CatId
##WHERE C.catname = 'Videography'
Order by sortOrder
Giving us
+----+------------+-----------------------------------------------+-------------+--------+-----------+----------+-------+
| | Image | FileURL | catname | status | sortorder | parentID | CatID |
+----+------------+-----------------------------------------------+-------------+--------+-----------+----------+-------+
| 1 | guid1.jpg | https://drive.google.com/BusinessID/Postings/ | Real Estate | 1 | 1 | NULL | 1 |
| 2 | guid4.jpg | https://drive.google.com/BusinessID/Postings/ | commercial | 1 | 2 | NULL | 2 |
| 3 | guid6.jpg | https://drive.google.com/BusinessID/Postings/ | Videography | 1 | 3 | NULL | 3 |
| 4 | guid10.jpg | https://drive.google.com/BusinessID/Postings/ | Other | 1 | 4 | NULL | 4 |
| 5 | guid11.jpg | https://drive.google.com/BusinessID/Postings/ | LackingMCVE | 1 | 5 | NULL | 5 |
+----+------------+-----------------------------------------------+-------------+--------+-----------+----------+-------+
Which of the following queries style is better for performance?
Basically, I'm returning many related records into one row with GROUP_CONCAT and I need to filter by another join on the GROUP_CONCAT value, and I will need to add many more either joins/group_concats/havings or sub queries in order to filter by more related values. I saw that, officially, LEFT JOIN was faster, but I wonder if the GROUP_CONCAT and HAVING through that off.
(This is a very simplified example, the actual data has many more attributes and it's reading from a Drupal MySQL architecture)
Thanks!
Main Records
+----+-----------------+----------------+-----------+-----------+
| id | other_record_id | value | type | attribute |
+----+-----------------+----------------+-----------+-----------+
| 1 | 0 | Red Building | building | |
| 2 | 1 | ACME Plumbing | attribute | company |
| 3 | 1 | east_side | attribute | location |
| 4 | 0 | Green Building | building | |
| 5 | 4 | AJAX Heating | attribute | company |
| 6 | 4 | west_side | attribute | location |
| 7 | 0 | Blue Building | building | |
| 8 | 7 | ZZZ Mattresses | attribute | company |
| 9 | 7 | south_side | attribute | location |
+----+-----------------+----------------+-----------+-----------+
location_transaltions
+-------------+------------+
| location_id | value |
+-------------+------------+
| 1 | east_side |
| 2 | west_side |
| 3 | south_side |
+-------------+------------+
locations
+----+--------------------+
| id | name |
+----+--------------------+
| 1 | Arts District |
| 2 | Warehouse District |
| 3 | Suburb |
+----+--------------------+
Query #1
SELECT
a.id,
GROUP_CONCAT(
IF(b.attribute = 'company', b.value, NULL)
) AS company_value,
GROUP_CONCAT(
IF(b.attribute = 'location', b.value, NULL)
) AS location_value,
GROUP_CONCAT(
IF(b.attribute = 'location', lt.location_id, NULL)
) AS location_id
FROM
records a
LEFT JOIN records b ON b.other_record_id = a.id AND b.type = 'attribute'
LEFT JOIN location_translations lt ON lt.value = b.value
WHERE a.type = 'building'
GROUP BY a.id
HAVING location_id = 2
Query #2
SELECT temp.* FROM (
SELECT
a.id,
GROUP_CONCAT(
IF(b.attribute = 'company', b.value, NULL)
) AS company_value,
GROUP_CONCAT(
IF(b.attribute = 'location', b.value, NULL)
) AS location_value
FROM
records a
LEFT JOIN records b ON b.other_record_id = a.id AND b.type = 'attribute'
WHERE a.type = 'building'
GROUP BY a.id
) as temp
LEFT JOIN location_translations lt ON lt.value = temp.location_value
WHERE location_id = 2
Using JOIN is preferable in most cases, because it helps optimizer to understand which indexes he can to use. In your case, query #1 looks good enough.
Of course, it works only if tables has indexes. Check table records has indexes on id, other_record_id, value and type columns, table location_translations on value
I believe this is a pretty simple thing, and I swear I've done it before but I can't remember how.
So let's say I have a one-to-many relationship. I want to JOIN the two tables, but not allow duplicates for the left table.
SQLFIDDLE
So based on the above SQLFiddle, my results would be:
categories.title | items.NAME | items.category_id
-----------------------------------------------------
red | apple | 1
red | car | 1
red | paper | 1
yellow | lego | 2
yellow | banana | 2
blue | pen | 3
I want it to be:
categories.title | items.NAME | items.category_id
-----------------------------------------------------
red | apple | 1
NULL | car | 1
NULL | paper | 1
yellow | lego | 2
NULL | banana | 2
blue | pen | 3
My reasoning is that this way, I can easily loop over the results without having to do any further processing with PHP.
You can replace the values with something like this:
select
case when rownum = 1 then title else null end title,
name,
category_id
from
(
SELECT c.title,
i.name,
i.category_id,
#row:=(case when #prev=title and #precat=category_id
then #row else 0 end) + 1 as rownum,
#prev:=title ptitle,
#precat:=category_id pcat
FROM items AS i
INNER JOIN categories AS c
ON c.id = i.category_id
order by i.category_id, c.title
) src
order by category_id, rownum
See SQL Fiddle with Demo
The result is:
| TITLE | NAME | CATEGORY_ID |
---------------------------------
| red | apple | 1 |
| (null) | car | 1 |
| (null) | paper | 1 |
| yellow | lego | 2 |
| (null) | banana | 2 |
| blue | pen | 3 |
It might be a long time ago when this was post. But I'll post my answer to the future readers. There is another process that is light and quick to understand.
You can make good use of variables. No subqueries are necessary.
SET #previous:="";
SELECT
IF(C.title=#previous, "", #previous:=C.title) AS Titles,
I.name, I.category_id
FROM items I
INNER JOIN categories AS C ON C.id = I.category_id
ORDER BY I.id, I.name
#previous is the variable that is being used.
SQL FIDDLE DEMO