mysql combined query, ids from comma separated list - mysql

I am not that familiar with mysql, so do not exactly not how sample the query correctly. I am working with wordpress and to illustrate what I would like to select please see the image below:
I have the ID of one special post. I would like to get all other Posts that are connected to it in the following way:
In the posts_meta table can exist entries, whose post_id matches the given ID. One of these entries meta_key is of a certain value and the meta_value of that very entry is a comma separated list of post_id's. I would like to Select * for each of Posts whose ID is in that comma separated list
I started with the following:
SELECT *
FROM prefix_posts AS a
JOIN prefix_postmeta AS b ON ( a.ID = b.post_id )
WHERE … //??
but I have no idea how to finish the query. How can I select the ids, to select posts in turn? I found SO answers dealing with FIND_IN_SET, but I do not want to test if a given ID is in the set, I the more need something like »STR_SPLIT« in a subquery.

I would like to Select * for each of Posts whose ID is in that comma separated list
Why not using FIND_IN_SET method ?, it can help you for your problem
This query return all posts whose have id in meta_value field from meta row having your "special post id" as post_id.
SELECT * FROM Post a, meta b
WHERE FIND_IN_SET(a.id, b.linked)>0 AND b.post_id= $id_post;
Tried on SQLFiddle, it seems to work.
Add a GROUP BY clause if you want avoid duplicates.

Related

How to Include/Exclude array of IDs from a relationship/pivot table and avoid duplicates?

Let's say you have
records table with id and name
tags table with id and name
records_tags with record_id and tags_id (relationship table)
Now you want to run a query to include records that have X tags and exclude records that have X tags.
You could do INNER JOIN, but the challenge here is, when there are many tags to a record, it creates duplicates within the results.
Example:
inner join `records_tags` on `records_tags`.`record_id` = `records`.`id`
and `records_tags`.`tag_id` in (?) and `records_tags`.`tag_id` not in (?)
As for the Laravel side, Ive used:
$records->join('records_tags', function ($join) use($include, $exclude) {
$join->on('records_tags.record_id','=','records.id');
if ($include) $join->whereIn('records_tags.tag_id',$include);
if ($exclude) $join->whereNotIn('records_tags.tag_id',$exclude);
});
Could there be a better solution to handle this or a way to ask for it to create unique or distinct rows, the goal of the join is only to include or exclude the actual records themselves from the results?
Edit:
The only other thing I can think of is doing something like this, still have to run tests to see accuracy, but for a crude solution
Edit 2: This doesn't appear to work on NOT IN as it creates duplicates.
$records->join(\DB::raw('(SELECT tag_id, record_id FROM records_tags WHERE records_tags.tag_id IN ('.implode(',',$include).'))'),'records_tags.record_id','=','records.id');
The conditions in the ON clause:
... and `records_tags`.`tag_id` in (?) and `records_tags`.`tag_id` not in (?)
do not exclude from the results the ids of the records that you want to exclude.
Any id that is linked to any of the wanted tags will be returned even if it is also linked to an unwanted tag, because the joins return 1 row for each of the linked tags.
What you can use is aggregation and the conditions in the HAVING clause:
SELECT r.id, r.name
FROM records r INNER JOIN records_tags rt
ON rt.record_id = r.id
GROUP BY r.id -- I assume that id is the primary key of records
HAVING SUM(rt.tag_id IN (?)) > 0
AND SUM(rt.tag_id IN (?)) = 0;
or, if you want the ids that are linked to all the wanted tags, use GROUP_CONCAT():
SELECT r.id, r.name
FROM records r INNER JOIN records_tags rt
ON rt.record_id = r.id
GROUP BY r.id
HAVING GROUP_CONCAT(rt.tag_id ORDER BY rt.tag_id) = ?;
In this case you will have to provide for the wanted tags ? placeholder a sorted comma separated list of ids.

Wordpress SQL data query layout

I am using SQL Executioner in Wordpress Admin and trying to get a list of data from a table (wp_postmeta) using the following:
SELECT post_id, meta_value from wp_postmeta
WHERE meta_key = "_wprm_reservation_name"
UNION
(SELECT post_id, meta_value from wp_postmeta
WHERE meta_key = "_wprm_reservation_phone_number");
This returns the information that I require but the layout is wrong. I am getting two columns: one with the post_id number and meta_value (persons name) listed then after all those I am getting the post_id number repeated and the telephone number.
Ideally I am trying to get the phone number to be placed next to the persons name. The post_id is the key as the number is used for both the name and phone number.
I have tried number variations trying to understand the UNION statement but cannot get this to work. Can anyone advise please where I am going wrong here?
Union working like this, see the documentation. What you need is a subquery, or a join. This is with subquery:
SELECT wppm.post_id, wppm.meta_value,
(SELECT wppmphone.meta_value FROM wp_postmeta wppmphone
WHERE wppmphone.meta_key = "_wprm_reservation_phone_number"
AND wppmphone.post_id = wppm.post_id) AS phoneNum
FROM wp_postmeta wppm WHERE meta_key = "_wprm_reservation_name";
This is one query, I just separated the subquery by new lines to be readable. This is not tested, but it should like something like this.
Note, I am using aliases for the table names.

CONCAT() result containing CONCAT()

Database setup:
http://sqlfiddle.com/#!2/4d1c2/1
Following query selects all tags which belongs to productID and their places, comma separated:
SELECT CONCAT_WS(',', GROUP_CONCAT(Tags.Name))
FROM `ProductTags`
LEFT JOIN Tags ON ProductTags.TagID = Tags.TagID
WHERE `ProductID` = 46356
GROUP BY DisplayOrder
It can contain 1-3 rows.
More complex query shows category, full of (like 50-100) products.
I want all tags be available at once, pass them to juery and then display.
The question is: how can i concat() this query into one field, so i only have one big query, or should i handle it with php and have like 100 queries at page?
I don´t know if I get you right, but this could be one solution:
SELECT CONCAT_WS(',', GROUP_CONCAT( DISTINCT Tags.Name))
FROM `ProductTags`
LEFT JOIN Tags ON ProductTags.TagID = Tags.TagID
This will show you all Tags for all productTags. (DISTINCT makes the names unique)

select count as a computed column?

I have a table named "likes" with this structure:
id - auto generated number,
bywho - user that likes someone ,
identifier - the liked user,
tip - the category of the like
i'm trying make a list with the most liked users(identifier), my problem is:
i need to generate the ammount of likes as a computed column in the list...
here is what i tried:
SELECT u.bywho,u.identifier COUNT(DISTINCT inv_by.identifier) AS lol
FROM likes u
LEFT JOIN likes inv_by ON u.identifier = inv_by.identifier
WHERE inv_by.identifier= $this->who AND tip='profil'
GROUP BY u.identifier ORDER BY lol DESC
I expect this isn't working because of the missing comma and grouping hasn't occured by u.bywho. The problem with doing that is it will give you a breakdown of the count by the person being liked and who liked them. Assuming a person can never be liked more than once, the count would always be one.
Try adding the comma after u.identiier in the select clause as mentioned by another reply.
If that doesn't work try grouping by u.who as well.
If that doesn't work as expected please explain what you expect a liitle more.
I'm guessing you may want to remove something from the select clause. Whatever non-aggregate is left in the select clause needs to be grouped upon.

Mysql Query - Joins causing confusion for me in this query

I have a query that returns results related to items that match a specific category...
There are 3 mysql tables that results to this, items, categories and item_categories.
These i assume are self explanatory, but the latter, is a linking table that links any specific item to any specific category, using a match of id's.
The items table contains one row, with an id value of 1.
The categories table is filled with 15 rows, with id values of 1-15.
the item_categories table contains one row, the item_id value is 1 and the category_id value is 5.
This is the mysql query in its php form:
$catResultQuery = "
SELECT i.id, name, price
FROM items i
INNER JOIN item_categories
ON i.id = item_id
INNER JOIN categories c
ON category_id = c.id
WHERE MATCH (c.id)
AGAINST ('{$_SESSION['input']}' IN BOOLEAN MODE)
ORDER BY name
";
The session variable has a value of 5, but for some reason, this query displays a 0 result set.
Even when i run the query in php myadmin, it returns 0 rows.
And i am confused, because in my head, the logic behind all of this seems fairly simple, but for some reason i get 0? Does anyone have any idea where i have gone wrong with this?
Any advice and input would be greatly appreciated, thank you!!
Ok, I see now that you're building the SQL dynamically. If that's the case, then this should work:
SELECT i.id, name, price
FROM items i
INNER JOIN item_categories
ON i.id = item_id
INNER JOIN categories c
ON category_id = c.id
WHERE c.id
IN ('{$_SESSION['input']}')
ORDER BY name
Just make sure '{$_SESSION['input']}' is comma delimited and be aware that this carries the risk of SQL injection because you're constructing the SQL on the fly.