Counting matches in mysql - mysql

I need to make a query that will match blogs that have matching tag_id in table tags_blogs. There is another table that contains the actual tags which I am not concerned about at this stage.
How do I take this table contents:
reference_id tag_id blog_id
1 1 1
2 2 1
3 10 6
4 11 6
5 10 7
6 11 7
7 11 8
And return this where (for example) blog_id = 6:
blog_id total_matches
7 2
8 1
In other words return any blog's ids that have matching tag_id to the parameter provided, as well as a count of how many matches were achieved.
This is the code I have so far (I am way off so far):
SELECT blog_id FROM tags_blogs WHERE blog_id = 6

You need a subquery to select all of 6 (or whatever blog id) tags and if a blog has a tag id IN that subquery it gets selected, then groups same blog_ids together and counts them.
SELECT
a.blog_id,
count(*) as total_matches
FROM
tags_blogs as a
WHERE
a.tag_id IN
( SELECT tag_id FROM tags_blogs WHERE b.blog_id=6 ) AND
a.blog_id!=6
GROUP BY a.blog_id
will return results like
blog_id total_matches
7 2
8 2

From your comments, here's more like what you are looking for. Note that this particular query isn't necessarily optimal
select tb.blog_id, count(*)
as total_matches
from tags_blogs tb
where tag_id in (select distinct tag_id from tags_blogs where blog_id = 6)
and blog_id != 6
group by blog_id
Link to SQL Fiddle
You might find that this is a little more efficient in some circumstances, or easier to create:
select tb.blog_id, count(*)
as total_matches
from tags_blogs tb
join tags_blogs tb1 on tb1.tag_id = tb.tag_id and tb1.blog_id != tb.blog_id
where tb1.blog_id = 6
group by tb.blog_id;

Related

mysqli query Order by priority based on 4 different tables

table_store
store_id title slug
1 Jabong jabong
2 Amazon amazon
table_coupon
coupon_id title store_id
1 Now 50% Off 1
2 New 2020 Sale 2
table_tag
tag_id title priority
1 Latest 5
2 Trending 4
3 Hot 3
table_tag_bind
id tag_id main_id(is coupon_id)
1 1 1
2 1 2
3 2 1
How can i list the products related to store based on tag priority. But dont repeat the same product if it has more than 1 tag. higher the number more tha priority:
my query: please what is wrong in this query?
SELECT DISTINCT(t1.`coupon_id`), t1.`title`
FROM `coupon` AS t1
LEFT JOIN `tag_bind` AS t2 ON t1.coupon_id = t2.main_id
LEFT JOIN `tag` AS t3 ON t3.id = t2.tag_id
WHERE t1.`store_id`='1'
ORDER BY t3.`priority` DESC
You want to order rows in coupons based on their maximum priority in table tag. I would suggest using a correlated subquery for ordering; this seems to me like the simplest way to phrase your requirement:
select c.coupon_id, c.title
from coupon as c
where c.store_id = 1
order by (
select max(t.priority)
from tag_bind tg
inner join tag t on t.id = tg.tag_id
where tg.main_id = c.coupon_id
) desc

Select values on one column having an identical set of values on another column

I have a "relational table" that stores which post has which tags. Just like Stack Overflow, a post can have many tags, and a tag can have many posts.
The table only has two columns and it looks like this:
pid tid
1 3
1 4
2 1
2 3
2 4
3 1
3 3
3 4
4 1
4 3
5 1
5 3
6 2
6 4
In the above table, post 2 and 3 have an identical set of tags (values on another column tid), and so are post 4 and 5.
I want to select all posts (post IDs) where there exists another post with the same set of tid, so the query should return 2 3 4 5 from column pid.
I'm running on MariaDB 10.1.38.
Here's my own attempt but apparently it fails:
SELECT p.pid
FROM post_tags AS p
WHERE EXISTS (
SELECT *
FROM post_tags AS p2
WHERE
GROUP_CONCAT(p.tid SEPARATOR ',') = GROUP_CONCAT(p2.tid SEPARATOR ',')
GROUP BY p2.pid
)
GROUP BY p.pid;
MariaDB told me:
ERROR 1111 (HY000): Invalid use of group function
GROUP_CONCAT() is an aggregate function, so you can't apply it in the WHERE clause, as it's evaluated in the SELECT clause (this happens after WHERE).
Also note, that you should add an ORDER BY in the GROUP_CONCAT() function. There's no guaranteed order in a relational database, unless you specifically specify it.
You could do it like this:
SELECT t1.pid FROM
(
SELECT
pid, GROUP_CONCAT(tid ORDER BY tid) AS gctid
FROM t t1
GROUP BY pid
) t1
JOIN (
SELECT
pid, GROUP_CONCAT(tid ORDER BY tid) AS gctid
FROM t t1
GROUP BY pid
) t2 ON t1.pid != t2.pid AND t1.gctid = t2.gctid
see it working live in an sqlfiddle

Unknown column in WHERE clause in subquery

I have pages table which I'm trying to truncate.
I need to leave last 10 versions of each page (page is identified by uid).
id----|----uid----|----version
1 ----|---- 1 ----|---- 1
2 ----|---- 1 ----|---- 2
3 ----|---- 1 ----|---- 3
4 ----|---- 1 ----|---- 4
5 ----|---- 2 ----|---- 1
6 ----|---- 2 ----|---- 2
...........
55 ----|---- 1 ----|---- 23
56 ----|---- 2 ----|---- 14
57 ----|---- 2 ----|---- 15
I've tried with this MySQL query:
DELETE FROM pages AS p WHERE p.id IN (
SELECT Versions.id FROM
(SELECT q.id FROM pages AS q WHERE p.uid = q.uid ORDER BY q.version DESC LIMIT 10)
AS Versions
)
but above SQL returns:
Unknown column 'p.uid' in 'where clause'
On Stackoverflow is loads of answers for similar questions like mine but as I'm not SQL ninja I wasn't able to convert any of these to fit my problem.
I don't want to overkill my query as well.
There must be some simple answer to this.
I can achieve needed truncation in MSSQL Server with query below:
DELETE FROM pages WHERE id NOT IN (
SELECT Versions.id FROM
(SELECT TOP (10) q.id FROM pages AS q WHERE pages.uid = q.uid ORDER BY q.version DESC)
AS Versions
)
Thanks
You don't need to co-ordinate the queries together here; just select a list of IDs to delete- the tables are the same
DELETE FROM pages WHERE id NOT IN
(SELECT TOP (10) id FROM pages ORDER BY q.version DESC)
You can't "order by" a delete query..
If youre after the MySQL version, and your version of MySQL doesnt support LIMIT for subqueries, and it doesn't support window functions like this:
delete from pages where id in
(select id from
(select id, row_number() over(order by dt desc) as rown from pages) a where a.rown > 10)
)
then you could consider something like:
CREATE table x as SELECT * FROM pages ORDER BY q.Version DESC LIMIT 10
TRUNCATE /*or delete from*/ pages
INSERT INTO pages SELECT * FROM x
DELETE PG FROM pages PG
LEFT JOIN
(
SELECT q.id FROM pages AS q ORDER BY q.version DESC LIMIT 10 OFFSET 0
) Versions ON Versions.ID=PG.ID
WHERE Versions.ID IS NULL
You can try above query.
DELETE p FROM pages AS p WHERE p.id IN (
SELECT Versions.id FROM
(SELECT q.id FROM pages AS q WHERE p.uid = q.uid ORDER BY q.version DESC LIMIT 10)
AS Versions
)
Check if this works..

Select the first 5 rows and get count

I'm trying to write a mysql query:
first select 5 rows and then get count with a where
first select 5 rows
table
id user_id
--------
1 1
2 2
3 3
4 1
5 1
6 4
7 3
8 1
id user_id
----------
1 1
2 2
3 3
4 1
5 1
And then get count this table where user_id =1
result = 3
You can try somthing like that
Select count(*) From
(Select * From T
order by ID asc Limit 5) as child
where user_id = 1
Looks like you want to present two different result sets together. You need to use a JOIN for this. Something like so will do the trick for you.
SELECT T.*,c.cnt
FROM T
JOIN ( SELECT COUNT(*) cnt FROM T where user_id = 1 ) c
LIMIT 5
The subquery generates your count as a one-row resultset, and the JOIN (which lacks an ON condition) puts it into every row of your other resultset.
If you wanted to show five rows from your table, and have each row mention the count for the userid in that row, you could do this.
SELECT T.*,c.cnt
FROM T
JOIN ( SELECT COUNT(*) cnt, user_id
FROM T
GROUP BY user_id
) c ON T.user_id = c.user_id
LIMIT 5
The way that summary (COUNT(), etc) queries and detail queries work together is a little intricate, but you will figure it out.
Beware, though: If you do a LIMIT without first doing an ORDER BY, MySQL is free to return any five rows it pleases.

How to trim this table in mysql?

I am a sql noob and not sure how to explain this. So here is what I'm trying to achieve:
Original table
id node_id tag_id
-------------------------
1 10 3
2 10 4
3 10 1
4 11 7
5 11 8
Trimmed table:
id node_id tag_id
-------------------------
1 10 3
4 11 7
It should be simple but I really left clueless, so appreciate your help.
It is unclear exactly what you want to do, but the following produces the output you specify:
select min(id), node_id, min(tag_id)
from table t
group by node_id;
EDIT:
If you want to delete rows, then use join:
delete o
from original_table ot left join
(select min(id) as id
from original_table
group by node_id
) tokeep
on ot.id = tokeep.id
where tokeep.id is null;
This uses a left join to match to the minimum id for each node_id. These are kept -- only non-matches are deleted.