I have tow tables like
users
id | name
_______________
1 | one
2 | two
3 | three
4 | four
5 | five
6 | six
employees
id | userId | reportedTo
_________________________
1 | 1 | null
2 | 2 | 1
3 | 3 | 2
4 | 4 | 3
5 | 5 | 4
6 | 6 | 5
I need something like
if I run query for some user then it will return all the record which reportedTo is this user and other users which reportedTo is reportedTo this user
Like:
if I run this query for user 1 then it will return all the record accept userId 1 from employees
id | userId | reportedTo
_________________________
2 | 2 | 1
3 | 3 | 2
4 | 4 | 3
5 | 5 | 4
6 | 6 | 5
if I run query for userId 4 then it will return recornds with userId 5 and 6 from employee table
id | userId | reportedTo
_________________________
5 | 5 | 4
6 | 6 | 5
can anyone help me with this.
Thanks in advance
You can use a recursive CTE:
with recursive cte(i, u, r) as (
select * from employees where reportedTo = 1
union all
select e.* from cte c join employees e on c.u = e.reportedTo
)
select c.i id, c.u userId, c.r reportedTo from cte c;
Output:
id
userId
reportedTo
2
2
1
3
3
2
4
4
3
5
5
4
6
6
5
See demo
Related
I have 3 tables, user_tag, article_tag, article_ignored. I want to fetch only those articles of user_id = 48 for which at least one article tags matches with user tag. I am stuck in this since long time and don't have any idea how to achieve this.
The table structure is as follows:
article_ignored table
id | user_id
1 | 48
2 | 48
3 | 48
article_tag table
id | article_id | tag_id
1 | 1 | 1
2 | 1 | 5
3 | 1 | 7
4 | 2 | 2
5 | 2 | 8
6 | 3 | 3
7 | 3 | 2
user_tag table
id | user_id | tag_id
1 | 48 | 2
2 | 48 | 3
Required output:
article_ignored
id
2
3
You can use NOT EXISTS:
SELECT id, user_id
FROM article_ignored AS ai
WHERE EXISTS (SELECT 1
FROM article_tag AS at
JOIN user_tag AS ut ON at.tag_id = ut.tag_id
WHERE ai.id = at.article_id)
Demo here
I have the following table:
+----+-------------+-----------------+-----------+----------------+
| id | link_id[FK] | category_id[FK] | parent_id[FK] | sort_order |
+----+-------------+-----------------+-----------+----------------+
| 1 2 1 1 1 |
| 2 2 133 1 2 |
| 3 3 2 2 1 |
| 4 3 200 2 2 |
| 5 3 333 200 3 |
| 6 4 1 1 1 |
| 7 5 3 3 1 |
| 8 5 133 3 2 |
| 9 5 223 133 3 |
| 10 5 456 223 4 |
+-----------------------------------------------------------------+
I need to be able to SELECT all rows with the same link_id, but using the category_id as the condition. So here is the example result I am looking for.
+----+-------------+-----------------+-----------+----------------+
| id | link_id[FK] | category_id[FK] | parent_id[FK] | sort_order |
+----+-------------+-----------------+-----------+----------------+
| 1 2 1 1 1 |
| 2 2 133 1 2 |
| 7 5 3 3 1 |
| 8 5 133 3 2 |
| 9 5 223 133 3 |
| 10 5 456 223 4 |
+-----------------------------------------------------------------+
I've tried this query, but it only returns the rows that equal category_id 133.
SELECT *
FROM table a
WHERE (a.object_id,a.category_id) IN (
SELECT b.link_id,b.link_id
FROM table b
WHERE b.category_id = 133
AND a.link_id = b.link_id
) ORDER BY a.sort_order
I've also tried a SELF JOIN, which is basically what I need, but then I get separate columns and I need them combined like above.
You first need to get the link_ids from the table where category_id = 133, then query the table for all the rows with that link_id.
SELECT * FROM `table`
WHERE link_id IN (
SELECT link_id FROM `table`
WHERE category_id = 133
)
ORDER BY link_id, sort_order
DEMO: http://sqlfiddle.com/#!9/67eb4/5
You should also be able to do this with a "self join", too:
SELECT a.* FROM `table` a
JOIN `table` b ON a.link_id = b.link_id
WHERE b.category_id = 133
ORDER BY a.link_id, a.sort_order
DEMO: http://sqlfiddle.com/#!9/67eb4/6
I have a table named 'Product' like this
id | Category_id | ProductName | Quantity
...........................................
1 | 2 | ABC | 4
2 | 2 | DEF | 2
3 | 2 | GHI | 4
4 | 2 | JKL | 1
5 | 2 | MNO | 4
6 | 2 | PQR | 4
7 | 2 | STU | 4
8 | 3 | VWX | 4
9 | 3 | YZA | 4
10 | 3 | YAB | 4
11 | 3 | YCD | 4
12 | 4 | YEF | 4
13 | 5 | YGH | 4
I want to fetch product of Category_id 2 and 3 with limit 5.
Note : Product from each category must be display after applying limit.
Expected output: Fetched total five rows containing random data from each Category_id 2 and 3
Output :
id | Category_id | ProductName | Quantity
...........................................
5 | 2 | MNO | 4
6 | 2 | PQR | 4
7 | 2 | STU | 4
8 | 3 | VWX | 4
9 | 3 | YZA | 4
Data order may be changed
You can use variables:
SELECT id, Quantity, ProductName, Category_id
FROM (
SELECT id, Quantity, ProductName, Category_id,
#row_number:= CASE
WHEN #cid = Category_id THEN #row_number+1
ELSE 1
END AS row_number,
#cid:=Category_id
FROM (
SELECT id, Quantity, ProductName, Category_id
FROM products
WHERE Category_id IN (2, 3)
ORDER BY Category_id, RAND() ) s ) t
ORDER BY row_number, Category_id
LIMIT 5
The above query will select a total of 5 records from categories 2, 3, trying to balance the number of records fetched from each category: 3 records will be fetched from category 2, whereas 2 records will be fecthed from category 3.
SQL Fiddle Demo
One way to do is you may get the two queries separately and use UNION ALL
(
select *
from Product
where `Category_id ` = 2
order by ProductName desc
LIMIT 5
)
UNION ALL
(
select *
from Product
where `Category_id ` = 3
order by ProductName desc
LIMIT 5
)
So why not
7 | 2 | STU | 4
8 | 3 | VWX | 4
9 | 3 | YZA | 4
10 | 3 | YAB | 4
11 | 3 | YCD | 4
?
This result set corresponds perfectly with your stated criteria.
I have 4 tables:
users (id, name, email);
id | name | email
1 | ABC | abc#gmail.com
2 | XYZ | xyz#gmail.com
3 | AAA | aaa#yahoo.com
papers(id, title, content, created_by)
id | title | content | created_by
1 | This is title 1 | This is content 1 | 1
2 | This is title 2 | This is content 2 | 1
3 | This is title 3 | This is content 3 | 3
4 | This is title 4 | This is content 4 | 1
5 | This is title 5 | This is content 5 | 3
6 | This is title 6 | This is content 6 | 2
rating(id, paperId, star)
id | paperId | star
1 | 1 | 2
2 | 2 | 4
3 | 3 | 4
4 | 2 | 2
5 | 1 | 3
comments(id, paperId, msg)
id | paperId | msg
1 | 1 | abcd
2 | 2 | xxxx
3 | 2 | yyyy
4 | 3 | zzzz
5 | 1 | tttt
6 | 4 | kkkk
I want to get fields: papers.id, papers.title, papers.content, users.name,
AVG(rating.star), COUNT(comments.msg)
And I execute a query like:
SELECT papers.id, papers.title, papers.content, users.name,
AVG(rating.star) AS avg_star , COUNT(comments.msg) AS num_of_cmt
FROM papers
JOIN users ON users.id = papers.created_by
LEFT JOIN rating ON rating.paperId = papers.id
LEFT JOIN comments ON comments.paperId = papers.id
WHERE papers.id = 1
Then result is false at "num_of_cmt" field:
id title content name avg_star num_of_cmt
1 This is title 1 This is content 1 ABC 2.5000 4
Above, 'num_of_cmt' is 4 instead of 2. Why?
Both ratings and comments have multiple rows for paperid = 1. So, joining the tables yields four results, with the following ids:
ratings comments
1 1
1 5
5 1
5 5
Hence, the count is 4. You can fix the count by doing count(distinct comments.id). However, the average is going to be off.
One way to fix this problem is by aggregating ratings and comments in subqueries.
I have this 3 tables:
Users:
user_id|user_nick
1 | a
2 | b
Category:
cat_id|cat_type
1 | a
2 | b
3 | c
4 | d
Meta:
met_id|met_name|met_user|met_type
10 | bla | 1 | 1
11 | blabla | 2 | 2
12 | foo | 1 | 3
13 | blafoo | 2 | 4
14 | foofoo | 1 | 4
15 | foobla | 1 | 4
How can I return something like this ?
user_id|met_type|total
1 | 1 | 1
1 | 2 | 0
1 | 3 | 1
1 | 4 | 2
For just one user and not for all of them.
met_type is a foreign key from Category.
I've tried like this but no success :/
SELECT met_user, met_type, COUNT(*) FROM Meta GROUP BY met_user WHERE met_user = '1'
Query:
SELECT met_user, met_type, count(*)
FROM Meta
WHERE met_user='1'
GROUP BY met_type;
To get empty groups, you can use generateSeries() here:
SELECT m.met_user, g.meta_type, count(m)
FROM generate_series(1, 4) AS g(meta_type)
LEFT OUTER JOIN Meta AS m
ON m.met_user='1'
AND m.met_type=g.meta_type
GROUP BY g.meta_type, m.met_user
ORDER BY g.meta_type;
Check it out! I made an sql fiddle.