select rows with the same column values - mysql

Given the table structure below, how do I select only rows having the same root and level values for a given name and user_id?
Category
+----+---------+------+------+-------+
| id | user_id | name | root | level |
+----+---------+------+------+-------+
| 1 | 10 | wzq | 1 | 1 |
| 2 | 11 | xyz | 2 | 1 |
| 3 | 10 | xyz | 2 | 2 |
| 4 | 10 | xyz | 2 | 2 |
+----+---------+------+------+-------+
What I have now also selects rows that do not have the same root and level
SELECT `c`.`id`, `c`.`user_id`, `c`.`name`, `c`.`root`, `c`.`level`
FROM `category` `c`
WHERE c.id IN (SELECT d.id FROM category AS d WHERE c.root=d.root AND c.level=d.level ) AND c.user_id = 10 AND c.name = 'xyz'
ORDER BY `c`.`id`
For the above example only the 3rd and 4th rows should be returned

Try this one for select only rows having the same root and level simply root=level
SELECT `id`, `user_id`, `name`, `root`, `level`
FROM `category`
WHERE root=level AND user_id = 10 AND `name` = 'xyz'
ORDER BY `id`

SELECT x.*
FROM my_table x
JOIN my_table y
ON y.user_id = x.user_id
AND y.root = x.root
AND y.level = x.level
AND y.id <> x.id
WHERE x.user_id = 10

try this:
SELECT *
FROM
(
SELECT root, level
FROM category
WHERE name = 'xyz' AND user_id = 10
) x JOIN category c ON x.root = c.root

Related

MySQL - JOIN columns of table1 with AVG of two columns from table2 and table3

I am trying to combine columns of the following 3 tables.
pages:
*id* | *identifier* | reference | url | ...
-------------------------------------------------------
1 | 1 | page one | http://... | ...
2 | 3 | page two | ..... | ...
3 | 23 | page three | ..... | ...
4 | 25 | page four | ..... | ...
5 | 43 | page five | ..... | ...
comments:
page_id | *rating* | comment | is_approved | name | ...
-------------------------------------------------------
1 | 4 | bla bla | 1 | joe | ...
2 | 5 | more bla | 1 | jim | ...
2 | 3 | blub | 1 | jill | ...
3 | 1 | blubblub | 1 | jack | ...
4 | 2 | hey ho | 0 | jimbo| ...
5 | 4 | huhu | 1 | mike | ...
ratings:
page_id | *rating* | ip_address | ...
-----------------------------------
1 | 3 | ... | ...
1 | 2 | ... | ...
2 | 5 | ... | ...
3 | 4 | ... | ...
4 | 0 | ... | ...
5 | 2 | ... | ...
pages.id links to comments.page_id and ratings.page_id
More specifically, I'd like to get the average of comments.rating and ratings.rating AS 'star_total' and combine this new column with the corrosponding rows from "pages", so that I get a table structure like this: id, identifier, star_total.
This is what I have been dabbling with. I know its not how it should be. It's just a rough idea and as far as I got:
SELECT pages.id, pages.identifier, star_total
FROM pages LEFT JOIN
(
SELECT AVG(`rating`) FROM (
SELECT 'rating' FROM comments
WHERE `comments.is_approved = '1'
AND comments.rating != '0'
AND comments.page_id = ratings.page_id
UNION ALL
SELECT `rating`
FROM ratings
WHERE ratings.page_id = comments.page_id
) AS `star_total`
)
We could do something like this:
SELECT pages.id
, pages.identifier
, q.star_total
FROM pages
LEFT
JOIN ( SELECT t.page_id
, SUM(t.tot_rating)/SUM(t.cnt_rating) AS star_total
FROM ( SELECT c.page_id AS page_id
, SUM(c.rating) AS tot_rating
, COUNT(c.rating) AS cnt_rating
FROM comments c
WHERE c.is_approved = '1'
AND c.rating != '0'
GROUP BY c.page_id
UNION ALL
SELECT r.page_id -- AS page_id
, SUM(r.rating) -- AS tot_rating
, COUNT(r.rating) -- AS cnt_rating
FROM ratings r
GROUP BY r.page_id
) t
GROUP BY t.page_id
) q
ON q.page_id = pages.id
For large sets, those inline views (derived tables) are going to be expensive. A somewhat simpler approach to get an equivalent result, possibly exacerbating the performance issue with the inline view:
SELECT pages.id
, pages.identifier
, q.star_total
FROM pages
LEFT
JOIN ( SELECT t.page_id
, AVG(t.rating) AS star_total
FROM ( SELECT c.page_id AS page_id
, c.rating AS rating
FROM comments c
WHERE c.is_approved = '1'
AND c.rating != '0'
UNION ALL
SELECT r.page_id -- AS page_id
, r.rating -- AS rating
FROM ratings r
) t
GROUP BY t.page_id
) q
ON q.page_id = pages.id
I think you need to union the ratings data, then calculate the average per page, then join that result to the pages.
SELECT
p.id
, p.identifier
, u star_total
FROM pages AS p
LEFT JOIN (
SELECT
page_id
, AVG(rating) star_total
FROM (
SELECT
page_id
, rating
FROM comments
WHERE comments.is_approved = '1'
AND comments.rating != '0'
UNION ALL
SELECT
page_id
, rating
FROM ratings
) d
GROUP BY
page_id
) AS u ON p.id = u.id

Calculate sum on the records while joining two tables with a third table

I have three tables:
mysql> select * from a;
+----+---------+
| ID | Name |
+----+---------+
| 1 | John |
| 2 | Alice |
+----+---------+
mysql> select * from b;
+------+------------+----------+
| UID | date | received |
+------+------------+----------+
| 1 | 2017-10-02 | 5 |
| 1 | 2017-09-30 | 1 |
| 1 | 2017-09-29 | 4 |
+------+------------+----------+
mysql> select * from c;
+------+------------+------+
| UID | date | sent |
+------+------------+------+
| 1 | 2017-09-25 | 7 |
| 1 | 2017-09-30 | 2 |
| 1 | 2017-09-29 | 3 |
+------+------------+------+
If I try to calculate the total number of sent for John, it would be 12. And for received, it would be 10.
But if I try to join all three tables, the result is weird. Here is my query to join three tables:
mysql> select sum(sent), sum(received) from a
-> join c on c.UID = a.ID
-> join b on b.UID = a.ID
-> where a.ID = 1;
+-----------+---------------+
| sum(sent) | sum(received) |
+-----------+---------------+
| 36 | 30 |
+-----------+---------------+
But I need correct numbers (12 and 10, respectively). How can I have correct numbers?
You should join the aggregated result and not the raw tables
select a.uid, t1.received, t2.sent
from a
inner join (
select uid, sum(received) received
from b
group by uid
) t1 on t1.uid = a.id
inner join (
select uid, sum(sent) sent
from c
group by uid
) t2 on t2.uid = a.id
where a.id = 1
You could try below
select bx.id, recieved, sum(c.sent) sent from
(
SELECT a.id, sum(b.received) recieved
from a
INNER JOIN b
ON a.id=b.uid
group by a.id
) bx
INNER JOIN c
ON c.uid=bx.id
group by bx.id, bx.recieved;
>>>Demo<<<
This gets rid of the subquery, but introduces something else you might not want:
( SELECT uid, 'Received' AS direction, SUM(received) AS HowMany
WHERE uid = 1
GROUP BY uid )
UNION ALL
( SELECT uid, 'Sent' AS direction, SUM(sent) AS HowMany
WHERE uid = 1
GROUP BY uid )

mysql: group surrounding records by same field value

I have a table with a following structure and data:
id | type | title
--------------------------
1 | 1 | test 1
2 | 1 | test 2
3 | 2 | test 3
4 | 2 | test 4
5 | 1 | test 5
I need to group neighbor rows with the same type field values.
So the result should be like:
type |
------
1 |
2 |
1 |
Thanks in advance.
this should do the trick.. using user defined variables.
SELECT
type
FROM(
SELECT
type,
if(#a = type, #b, #b := #b + 1) as grouping_col,
#a := type
FROM testing
JOIN (select #a := 1, #b := 0) as temp
) as t
GROUP BY grouping_col;
SQL FIDDLE to play with
Here's one way - although a solution using variables will scale better...
DROP TABLE IF EXISTS my_table;
CREATE TABLE my_table
(id INT NOT NULL AUTO_INCREMENT PRIMARY KEY
,type INT NOT NULL
,title VARCHAR(12) NOT NULL
);
INSERT INTO my_table VALUES
(1,1,'test 1'),
(3,1,'test 2'),
(4,2,'test 3'),
(7,2,'test 4'),
(9,1,'test 5');
SELECT * FROM my_table;
+----+------+--------+
| id | type | title |
+----+------+--------+
| 1 | 1 | test 1 |
| 3 | 1 | test 2 |
| 4 | 2 | test 3 |
| 7 | 2 | test 4 |
| 9 | 1 | test 5 |
+----+------+--------+
SELECT a.id start
, MIN(c.id) End
, a.type
FROM
( SELECT x.*,COUNT(*) rank FROM my_table x JOIN my_table y ON y.id <= x.id GROUP BY x.id) a
LEFT
JOIN
( SELECT x.*,COUNT(*) rank FROM my_table x JOIN my_table y ON y.id <= x.id GROUP BY x.id) b
ON b.type = a.type
AND b.rank = a.rank - 1
LEFT
JOIN
( SELECT x.*,COUNT(*) rank FROM my_table x JOIN my_table y ON y.id <= x.id GROUP BY x.id) c
ON c.type = a.type
AND c.rank >= a.rank
LEFT
JOIN
( SELECT x.*,COUNT(*) rank FROM my_table x JOIN my_table y ON y.id <= x.id GROUP BY x.id) d
ON d.type = a.type
AND d.rank = c.rank + 1
WHERE b.id IS NULL
AND c.id IS NOT NULL
AND d.id IS NULL
GROUP
BY a.id;
+-------+------+------+
| start | End | type |
+-------+------+------+
| 1 | 3 | 1 |
| 4 | 7 | 2 |
| 9 | 9 | 1 |
+-------+------+------+

MySQL join and sum issue / combine queries

I have created a points example to demonstrate my issue.
A members can reward other members points, I am trying to build a query which will display the points a user has and points user has given.
Database Example
Members,
+----+----------+
| id | username |
+----+----------+
| 1 | user1 |
| 2 | user2 |
| 3 | user3 |
+----+----------+
Points,
+-------+--------+--------+
| IDFor | IDFrom | Pointz |
+-------+--------+--------+
| 1 | 2 | 5 |
| 1 | 2 | 5 |
| 3 | 1 | 2 |
+-------+--------+--------+
The return I am looking for is,
+-----------+--------+-------+
| username | Pointz | Given |
+-----------+--------+-------+
| user1 | 10 | 2 |
| user2 | 0 | 10 |
| user3 | 2 | 0 |
+-----------+--------+-------+
Both my queries return,
+-----------+--------+-------+
| username | Pointz | Given |
+-----------+--------+-------+
| user1 | 10 | 4 |
| user2 | 0 | 10 |
| user3 | 2 | 0 |
+-----------+--------+-------+
http://sqlfiddle.com/#!2/32ae6/6
SELECT a.`username`, sum(a.`Pointz`), sum(b.`Pointz`) FROM
(SELECT * FROM `members`
LEFT JOIN `Example`.`Points` AS p ON `members`.`id` = p.`IDFor` ) AS a
LEFT JOIN
(SELECT * FROM `members`
LEFT JOIN `Example`.`Points` AS n ON `members`.`id` = n.`IDFrom` ) AS b
ON a.id = b.id
GROUP BY a.`id`
http://sqlfiddle.com/#!2/32ae6/7
SELECT `members`.`username`,sum(p.`Pointz`),sum(n.`Pointz`)
FROM `members`
LEFT JOIN `Example`.`Points` as p ON p.`IDFor` = `members`.`id`
LEFT JOIN `Example`.`Points` as n ON n.`IDFrom` = `members`.`id`
GROUP BY `members`.`id`
Seems to be a common question that pops up but have not found a solution, all my other attempts from similar questions have not ended well, Thanks all.
This is what u want
select a.username, ifnull(Pointz, 0) Pointz, ifnull(Given, 0) Given from
(SELECT id, `username`, sum(`Pointz`) Pointz FROM `members`
LEFT JOIN `Points` ON `members`.`id` = `Points`.`IDFor` group by id) a
left join
(SELECT id, `username`, sum(`Pointz`) Given FROM `members`
LEFT JOIN `Points` ON `members`.`id` = `Points`.`IDFrom` group by id) b
on a.id = b.id
Try:
SELECT m.username,
COALESCE( pr.preceived, 0 ) as Pointz,
COALESCE( pg.pgiven, 0 ) as Given
FROM members m
LEFT JOIN ( SELECT IDFor, sum(pointz) as preceived
FROM Points
GROUP BY IDFor ) pr
ON m.id = pr.IDFor
LEFT JOIN ( SELECT IDFrom, sum(pointz) as pgiven
FROM Points
GROUP BY IDFrom ) pg
ON m.id = pg.IDFrom
http://sqlfiddle.com/#!2/32ae6/48
Try this:
SELECT m.`username`,
ifnull((SELECT sum(`Pointz`) FROM Points p
WHERE p.IDFor = m.id ), 0),
ifnull((SELECT sum(`Pointz`) FROM Points p
WHERE p.IDFrom = m.id ), 0)
FROM Members m
SQLFiddle

SQL Query selecting row with unique record in a table's column?

I'm having a problem with my query by selecting the rows with unique id in one column.
Here's my db looks like:
Table 1
user_id | user_name | user_email
1 john ex0#email
2 nathel ex1#email
3 bob ex2#email
Table 2
subs_id | user_id | prod_id
1 1 1
2 1 2
3 2 1
4 3 1
5 3 3
Table 3
prod_id | prod_name
1 Platinum
2 Gold
3 Steel
What I need to do is to select the user row from Table 1 join with Table 2 & 3 that has a unique record in Table 2 user_id column based on their subscription.
Example. I want to select the user subscribing only in platinum, so the output must be looks like this :
user_id | user_name | user_email | subs_id | user_id | prod_id | prod_id | prod_name
2 nathel ex1#email 3 2 1 1 Platinum
SELECT * from users u inner join subscription s on u.user_id = s.user_id
inner join products p on p.prod_id = s.prod_id
WHERE s.user_id IN (SELECT user_id from subscription GROUP by user_id HAVING count(user_id) = 1) AND s.prod_id = 1
The last piece of the puzzle has been omitted as an exercise for the reader...
DROP TABLE IF EXISTS users;
CREATE TABLE users
(user_id INT NOT NULL AUTO_INCREMENT PRIMARY KEY
,user_name VARCHAR(20) NOT NULL UNIQUE
,user_email VARCHAR(12) NOT NULL
);
INSERT INTO users VALUES
(1 ,'john','ex0#email'),
(2 ,'nathel','ex1#email'),
(3 ,'bob','ex2#email');
DROP TABLE IF EXISTS product_user;
CREATE TABLE product_user
(product_id INT NOT NULL
,user_id INT NOT NULL
,PRIMARY KEY (product_id,user_id)
);
INSERT INTO product_user VALUES
(1, 1),(2 ,1),(1 ,2),(1,3),(3,3);
DROP TABLE IF EXISTS products;
CREATE TABLE products
(product_id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,product_name VARCHAR(12) NOT NULL UNIQUE);
INSERT INTO products VALUES (1 ,'Platinum'),(2,'Gold'),(3,'Steel');
SELECT *
FROM product_user x
LEFT
JOIN product_user y
ON y.user_id = x.user_id
AND y.product_id <> x.product_id
WHERE x.product_id =1;
+------------+---------+------------+---------+
| product_id | user_id | product_id | user_id |
+------------+---------+------------+---------+
| 1 | 1 | 2 | 1 |
| 1 | 2 | NULL | NULL |
| 1 | 3 | 3 | 3 |
+------------+---------+------------+---------+
SELECT *
FROM product_user x
LEFT
JOIN product_user y
ON y.user_id = x.user_id
AND y.product_id <> x.product_id
JOIN users u
ON u.user_id = x.user_id
JOIN products p
ON p.product_id = x.product_id
WHERE p.product_name = 'Platinum';
+------------+---------+------------+---------+---------+-----------+------------+------------+--------------+
| product_id | user_id | product_id | user_id | user_id | user_name | user_email | product_id | product_name |
+------------+---------+------------+---------+---------+-----------+------------+------------+--------------+
| 1 | 1 | 2 | 1 | 1 | john | ex0#email | 1 | Platinum |
| 1 | 2 | NULL | NULL | 2 | nathel | ex1#email | 1 | Platinum |
| 1 | 3 | 3 | 3 | 3 | bob | ex2#email | 1 | Platinum |
+------------+---------+------------+---------+---------+-----------+------------+------------+--------------+
Hope so you are looking for this :
SELECT * FROM table1 as t1
inner join table2 as t2 on t1.user_id = t2.user_id
inner join table3 as t3 on t2.prod_id = t3.prod_id
where t3.prod_name = 'Platinum';
I think you can use DISTINCT to fetch unique recodes from database in query
SELECT DISTINCT
t1.`user_id` ,t1.`user_name`,t1.`user_email`,t2.`subs_id`,t2.`user_id`,t2.`prod_id`,t3.`prod_id` ,t3.`prod_name`
FROM Table1 t1
INNER JOIN Table2 t2
ON t1.`user_id`=t2.`user_id`
INNER JOIN Table3 t3
ON t2.`prod_id`=t3.`prod_id`
WHERE
t1.`user_id`='2'
Hope this will be helpful to you
Please! try below code snip
select t1.user_id ,t1.user_name,t1.user_email,
t2.subs_id,t2.user_id , t2.prod_id ,
t3.prod_id , t3.prod_name
from table2 t2 inner join table1 t1 on t2.user_id=t1.user_id
inner join table3 t3 on t3.prod_id=t2.prod_id and t2.prod_id =1