Select data from two related columns in MySql - mysql

table proyectos has two related columns, id_pro and id_padre
CREATE TABLE IF NOT EXISTS `proyectos` (
`id_pro` int(8) unsigned NOT NULL,
`ot_padre` int(8) unsigned NOT NULL,
`nom_pro` varchar(255) NOT NULL,
PRIMARY KEY (`id_pro`)
) DEFAULT CHARSET=utf8;
INSERT INTO `proyectos` (`id_pro`, `ot_padre`, `nom_pro`) VALUES
('1', '0', 'Proyecto 1'),
('2', '0', 'Proyecto 2'),
('3', '0', 'Proyecto 3'),
('4', '3', 'Proyecto hijo 1'),
('5', '3', 'Proyecto hijo 2');
CREATE TABLE IF NOT EXISTS `servicios` (
`id_ser` int(8) unsigned NOT NULL,
`id_pro` int(8) unsigned NOT NULL,
`nom_ser` varchar(255) NOT NULL,
PRIMARY KEY (`id_ser`)
) DEFAULT CHARSET=utf8;
INSERT INTO `servicios` (`id_ser`, `id_pro`, `nom_ser`) VALUES
('1', '1', 'Servicio a'),
('2', '1', 'Servicio b'),
('3', '3', 'Servicio c'),
('4', '3', 'Servicio d'),
('5', '4', 'Servicio e'),
('6', '5', 'Servicio e');
How can obtain all data from servicios with id_pro 3, and also all service with id_padre 3?
EDIT**
expected output
id_ser | id_pro | nom_ser |
3 | 3 | Servicio c |
4 | 3 | Servicio d |
5 | 4 | Servicio e |
6 | 5 | Servicio f |
schema and query
http://sqlfiddle.com/#!9/a1e0dc/1/0

You need an INNER join of the tables:
SELECT s.*
FROM servicios s INNER JOIN proyectos p
ON p.id_pro = s.id_pro
WHERE 3 IN (p.id_pro, p.ot_padre)
See the demo.
Results:
id_ser
id_pro
nom_ser
3
3
Servicio c
4
3
Servicio d
5
4
Servicio e
6
5
Servicio f

SELECT DISTINCT * FROM Servicios
WHERE id_pro = 3
OR id_pro IN
(SELECT id_pro
FROM Proyectos
WHERE id_padre = 3)
Outputs:
id_ser id_pro nom_ser
3 3 Servicio c
4 3 Servicio d
5 4 Servicio e

It seems to me that you're actually after this:
SELECT *
FROM servicios
WHERE id_pro = 3
UNION
SELECT s.*
FROM servicios s
JOIN proyectos p
ON p.id_pro = s.id_pro
WHERE p.ot_padre = 3;
(There are various ways of writing this, including a LEFT JOIN with COALESCE)

Related

Inner Join table with a maximum date

Please help me.
I have 2 table Users and Diseaselogs
1 user has many diseaselogs
I want to select all users and each user must be field date in diseaselogs is max
Data example
Users
id | name | age
1 | Nam | 21
2 | Thao | 23
3 | An | 19
Diseaselogs
id | logType | userId | date
1 | positive | 1 | 2021-06-21
2 | negative | 2 | 2021-06-22
3 | pending | 1 | 2021-06-24
4 | negative | 1 | 2021-06-26
5 | negative | 2 | 2021-06-21
6 | pending | 3 | 2021-06-23
7 | negative | 1 | 2021-06-24
8 | negative | 2 | 2021-06-25
9 | pending | 3 | 2021-06-28
Expect output
id | name | logId | logType | date
1 | Nam | 4 | negative | 2021-06-26
2 | Thao | 8 | negative | 2021-06-25
3 | An | 9 | pending | 2021-06-28
As ROW_NUMBER() doesn't support lower version of mysql i.e 5.7 to downwords. So I've tried here alternatives of ROW_NUMBER().
-- MySQL (V 5.6)
SELECT u.id, u.name, tmp.logId, tmp.logType, tmp.date
FROM users u
INNER JOIN (SELECT #row_no := IF(#prev_val = t.userId, #row_no + 1, 1) AS row_number
, #prev_val := t.userId AS userId
, t.date
, t.logType
, t.id AS logId
FROM Diseaselogs t,
(SELECT #row_no := 0) x,
(SELECT #prev_val := '') y
ORDER BY t.userId, t.date DESC ) tmp
ON u.id = tmp.userId
AND tmp.row_number = 1;
Please check url http://sqlfiddle.com/#!9/741b96/16
Also if your MySQL version is 5.8 then you can apply the below query where row_number() is used.
SELECT u.id, u.name, tmp.logId, tmp.logType, tmp.date
FROM users u
INNER JOIN (SELECT ROW_NUMBER() OVER (PARTITION BY userId ORDER BY date DESC) row_number
, userId
, date
, logType
, id AS logId
FROM Diseaselogs ) tmp
ON u.id = tmp.userId
AND tmp.row_number = 1;
in mysql 8 you can use ROW_NUMBER and an INNER JOIN
in prior versions you need to use another method for rownumber
Schema (MySQL v8.0)
CREATE TABLE Diseaselogs (
`id` INTEGER,
`logType` VARCHAR(8),
`userId` INTEGER,
`date` VARCHAR(10)
);
INSERT INTO Diseaselogs
(`id`, `logType`, `userId`, `date`)
VALUES
('1', 'positive', '1', '2021-06-21'),
('2', 'negative', '2', '2021-06-22'),
('3', 'pending', '1', '2021-06-24'),
('4', 'negative', '1', '2021-06-26'),
('5', 'negative', '2', '2021-06-21'),
('6', 'pending', '3', '2021-06-23'),
('7', 'negative', '1', '2021-06-24'),
('8', 'negative', '2', '2021-06-25'),
('9', 'pending', '3', '2021-06-28');
CREATE TABLE users (
`id` INTEGER,
`name` VARCHAR(4),
`age` INTEGER
);
INSERT INTO users
(`id`, `name`, `age`)
VALUES
('1', 'Nam', '21'),
('2', 'Thao', '23'),
('3', 'An', '19');
Query #1
SELECT
u.id, `name`, t1.id,`logType`, `date`
FROM
(SELECT
id,`logType`, `userId`, `date`
, ROW_NUMBER() OVER (PARTITION BY `userId` ORDER BY `date` DESC) rn
FROM
Diseaselogs) t1
INNER JOIN users u ON t1.userId = u.id
WHERE rn = 1;
id
name
id
logType
date
1
Nam
4
negative
2021-06-26
2
Thao
8
negative
2021-06-25
3
An
9
pending
2021-06-28
View on DB Fiddle
Schema (MySQL v8.0)
CREATE TABLE Diseaselogs (
`id` INTEGER,
`logType` VARCHAR(8),
`userId` INTEGER,
`date` VARCHAR(10)
);
INSERT INTO Diseaselogs
(`id`, `logType`, `userId`, `date`)
VALUES
('1', 'positive', '1', '2021-06-21'),
('2', 'negative', '2', '2021-06-22'),
('3', 'pending', '1', '2021-06-24'),
('4', 'negative', '1', '2021-06-26'),
('5', 'negative', '2', '2021-06-21'),
('6', 'pending', '3', '2021-06-23'),
('7', 'negative', '1', '2021-06-24'),
('8', 'negative', '2', '2021-06-25'),
('9', 'pending', '3', '2021-06-28');
CREATE TABLE users (
`id` INTEGER,
`name` VARCHAR(4),
`age` INTEGER
);
INSERT INTO users
(`id`, `name`, `age`)
VALUES
('1', 'Nam', '21'),
('2', 'Thao', '23'),
('3', 'An', '19');
Query #1
SELECT
u.id, `name`, `age`,`logType`, `date`
FROM
(SELECT
`logType`, `userId`, `date`
, ROW_NUMBER() OVER (PARTITION BY `userId` ORDER BY `date` DESC) rn
FROM
Diseaselogs) t1
INNER JOIN users u ON t1.userId = u.id
WHERE rn = 1;
id
name
age
logType
date
1
Nam
21
negative
2021-06-26
2
Thao
23
negative
2021-06-25
3
An
19
pending
2021-06-28
View on DB Fiddle

Mysql returning multiple row instead of one row with array of Images

Consider the following schema:
CREATE TABLE users (
id INT NOT NULL AUTO_INCREMENT,
name VARCHAR(45) NULL,
PRIMARY KEY (id)
);
CREATE TABLE attachments (
id INT NOT NULL,
name VARCHAR(45) NULL DEFAULT NULL,
filePath VARCHAR(255) NULL DEFAULT NULL,
thumbnailPath VARCHAR(255) NULL DEFAULT NULL,
PRIMARY KEY (id)
);
CREATE TABLE reviews (
id INT NOT NULL AUTO_INCREMENT,
productId INT NULL,
user_id INT NULL,
review VARCHAR(45) NULL,
rating INT NULL,
PRIMARY KEY (id));
CREATE TABLE review_attachments (
id INT NOT NULL AUTO_INCREMENT,
review_id INT NULL,
attachment_id INT NULL,
PRIMARY KEY (id));
INSERT INTO users (id, name) VALUES
('1', 'XYZ'),
('2', 'ABC'),
('3', 'EVE');
INSERT INTO attachments (id, name, filePath, thumbnailPath) VALUES
('100', 'f.png', '/resources/attachments/2020/f.png', '/resources/attachments/thumbnail/2020/f.png'),
('101', 'd.png', '/resources/attachments/2020/d.png', '/resources/attachments/thumbnail/2020/d.png'),
('102', 'g.png', '/resources/attachments/2020/g.png', '/resources/attachments/thumbnail/2020/g.png');
INSERT INTO reviews (id, productId, user_id, review, rating) VALUES
('1', '1', '1', 'Great Product', '5'),
('2', '1', '2', 'Good Product', '4'),
('3', '1', '3', 'Bad Product', '1');
INSERT INTO review_attachments (id, review_id, attachment_id) VALUES
('1', '1', '100'),
('2', '1', '101'),
('3', '1', '102');
When I query against this schema using the following query I am getting two rows with the same entries.
I am using JSON_ARRAYAGG to return an array it may be because of groupby.
Can anyone help me get this query right?
select
review, rating, u.name,reviews.createdAt,
(SELECT
JSON_ARRAYAGG(JSON_OBJECT("attachmentId", attachments.id,
'filePath', TRIM(CONCAT("${process.env.NODE_SERVER_API_HOST}", '/',attachments.filePath)),
'thumbnailPath', TRIM(CONCAT("${process.env.NODE_SERVER_API_HOST}", '/',attachments.thumbnailPath))
))
FROM attachments
WHERE attachments.id = ra.attachment_id) as reviewAttachments
from reviews
left join users as u on u.id = reviews.user_id
left join reviewAttachments as ra on ra.review_id = reviews.id
left join attachments as at on at.id = ra.attachment_id
where productId = 1
and reviews.isDeleted =0
and reviews.review is not null
limit 0,5
|review |rating| name | createdAt | reviewAttachments |
|:---- |:----:| -----:| ---------:| ----------------:
|Great Product | 5 | XYZ | 2020-11-04| [{"filePath": "${process.env.NODE_SERVER_API_HOST}/resources/attachments/2020/f.png", "attachmentId": 102, "thumbnailPath": "${process.env.NODE_SERVER_API_HOST}/resources/attachments/thumbnail/2020/f.png"}]
|Great Product | 5 | XYZ | 2020-11-04| [{"filePath": "${process.env.NODE_SERVER_API_HOST}/resources/attachments/2020/d.png", "attachmentId": 101, "thumbnailPath": "${process.env.NODE_SERVER_API_HOST}/resources/attachments/thumbnail/2020/d.png"}]
|Great Product | 5 | XYZ | 2020-11-04| [{"filePath": "${process.env.NODE_SERVER_API_HOST}/resources/attachments/2020/g.png", "attachmentId": 100, "thumbnailPath": "${process.env.NODE_SERVER_API_HOST}/resources/attachments/thumbnail/2020/g.png"}]
|Good Product | 4 | ABC | 2020-11-04| null
|Bad Product | 1 | EVE | 2020-11-04| null
Desired output:
|review |rating| name | createdAt | reviewAttachments |
|:---- |:----:| -----:| ---------:| ----------------:
|Great Product | 5 | XYZ | 2020-11-04| [{"filePath": "${process.env.NODE_SERVER_API_HOST}/resources/attachments/2020/f.png", "attachmentId": 102, "thumbnailPath": "${process.env.NODE_SERVER_API_HOST}/resources/attachments/thumbnail/2020/f.png"}, {"filePath": "${process.env.NODE_SERVER_API_HOST}/resources/attachments/2020/d.png", "attachmentId": 101, "thumbnailPath": "${process.env.NODE_SERVER_API_HOST}/resources/attachments/thumbnail/2020/d.png"}, {"filePath": "${process.env.NODE_SERVER_API_HOST}/resources/attachments/2020/g.png", "attachmentId": 100, "thumbnailPath": "${process.env.NODE_SERVER_API_HOST}/resources/attachments/thumbnail/2020/g.png"}]
|Good Product | 4 | ABC | 2020-11-04| null
|Bad Product | 1 | EVE | 2020-11-04| null
Notice: The above row with rating 5 is returning array of reviewAttachments associated with that review. My output is returning each row with duplicate entries of that rating with different review attachment.
select
review, rating, u.name,
(SELECT
JSON_ARRAYAGG(JSON_OBJECT("attachmentId", attachments.id,
'filePath', TRIM(CONCAT("${process.env.NODE_SERVER_API_HOST}", '/',attachments.filePath)),
'thumbnailPath', TRIM(CONCAT("${process.env.NODE_SERVER_API_HOST}", '/',attachments.thumbnailPath))
))
FROM review_attachments ra
left join attachments on attachments.id = ra.attachment_id
WHERE ra.review_id = reviews.id) as reviewAttachments
from reviews
left join users as u on u.id = reviews.user_id
where productId = 1
and reviews.review is not null
limit 0,5

Select query by comparing 2 table values

i have 2 tables (tbl_news and tbl_news_category)
tbl_news_category table is
cat_id cat_name general
1 name1 1
2 name2 1
3 name3 0
4 name4 1
5 name5 0
tbl_news table is
id cat_id title news_isimage
1 2 title1 1
2 5 title2 0
3 1 title2 1
4 3 title2 1
5 2 title2 1
6 5 title2 1
7 4 title2 1
8 5 title2 1
i want to get 5 random items from tbl_news which general value should be 1
i tried below code and its not working
SELECT
d.*
FROM
tbl_news d,
tbl_news_category p
WHERE
p.general = 1 AND d.news_isimage = 0
AND d.cat_id > 3
ORDER BY RAND()
LIMIT 5
but its giving news item with cat_id with general = 0
Do a proper join of the tables:
select n.*
from tbl_news n inner join tbl_news_category c
on c.cat_id = n.cat_id
where c.general = 1
order by rand() limit 5
You have also in your code the conditions:
news_isimage = 0 AND cat_id > 3
If you need them you can add them to the WHERE clause:
WHERE c.general = 1 AND n.news_isimage = 0 AND c.cat_id > 3
There is no data for your query available.
But do an INNER JOIN
CREATE TABLE tbl_news (
`id` INTEGER,
`cat_id` INTEGER,
`title` VARCHAR(6),
`news_isimage` INTEGER
);
INSERT INTO tbl_news
(`id`, `cat_id`, `title`, `news_isimage`)
VALUES
('1', '2', 'title1', '1'),
('2', '5', 'title2', '0'),
('3', '1', 'title2', '1'),
('4', '3', 'title2', '1'),
('5', '2', 'title2', '1'),
('6', '5', 'title2', '1'),
('7', '4', 'title2', '1'),
('8', '5', 'title2', '1');
CREATE TABLE tbl_news_category (
`cat_id` INTEGER,
`cat_name` VARCHAR(5),
`general` INTEGER
);
INSERT INTO tbl_news_category
(`cat_id`, `cat_name`, `general`)
VALUES
('1', 'name1', '1'),
('2', 'name2', '1'),
('3', 'name3', '0'),
('4', 'name4', '1'),
('5', 'name5', '0');
✓
✓
✓
✓
SELECT
tn.title
, tn.news_isimage
,tnc.cat_name
FROM tbl_news tn INNER JOIN tbl_news_category tnc ON tn.cat_id = tnc.cat_id
WHERE
tnc.general = 1
AND tn.news_isimage = 0
AND tnc.cat_id > 3
ORDER BY RAND()
LIMIT 5
title | news_isimage | cat_name
:---- | -----------: | :-------
db<>fiddle here

Select count of different values in mysql

I have two tables, A and B, structured as follows.
CREATE TABLE TableA (
`id` INTEGER,
`code` VARCHAR(1),
`type` VARCHAR(1)
);
INSERT INTO TableA
(`id`, `code`, `type`)
VALUES
('1', 'A', 'r'),
('2', 'A', 'o'),
('3', 'A', 'u'),
('4', 'B', 'h');
CREATE TABLE TableB (
`id` INTEGER,
`sid` INTEGER,
`code` VARCHAR(1)
);
INSERT INTO TableB
(`id`, `sid`, `code`)
VALUES
('1', '1', 'A'),
('1', '1', 'A'),
('1', '1', 'A'),
('2', '1', 'B'),
('2', '1', 'B'),
('1', '2', 'A'),
('1', '2', 'A'),
('2', '2', 'A');
the output of this query should be like this
sid r o u
1 3 2 0
2 2 1 0
table A has a foreign key from table B which is the id. what I want to get is how many times each sid accessed each type of table A.
Left join Table B to Table A and aggregate:
select b.sid,
sum(a.type = 'r') r,
sum(a.type = 'o') o,
sum(a.type = 'u') u
from TableB b left join TableA a
on b.id = a.id
group by b.sid
See the demo.
Results:
| sid | r | o | u |
| --- | --- | --- | --- |
| 1 | 3 | 2 | 0 |
| 2 | 2 | 1 | 0 |

Double GroupBy with Count and Dates Returns Wrong Dates

I have three tables to keep track of emails and their assigned categories: Email keeps the mail's content, Category lists the categories and Classification links an Email entry ID with a Category entry ID. Schema with sample data and query is available on SQLFiddle: http://sqlfiddle.com/#!9/a410a6/26/0
CREATE TABLE `Category` (
`id` int(6) unsigned NOT NULL,
`name` varchar(20) NOT NULL,
PRIMARY KEY (`id`)
) DEFAULT CHARSET=utf8;
CREATE TABLE `Mail` (
`id` int(6) unsigned NOT NULL,
`content` varchar(500) NOT NULL,
`date` datetime NOT NULL,
PRIMARY KEY (`id`)
) DEFAULT CHARSET=utf8;
CREATE TABLE `Classification` (
`id` int(6) unsigned NOT NULL,
`mail_id` int(6) unsigned NOT NULL,
`category_id` int(6) unsigned NOT NULL,
FOREIGN KEY (mail_id) REFERENCES Mail(id),
FOREIGN KEY (category_id) REFERENCES Category(id),
PRIMARY KEY (`id`)
) DEFAULT CHARSET=utf8;
INSERT INTO `Category` (`id`, `name`) VALUES
('1', 'Important'),
('2', 'Urgent'),
('3', 'Normal');
INSERT INTO `Mail` (`id`, `content`, `date`) VALUES
('1', 'Important Email', '2019-01-04T13:53:52'),
('2', 'Urgent Email', '2019-01-19T13:53:52'),
('3', 'Very Urgent Email', '2019-01-24T13:53:52'),
('4', 'Quite Urgent Email', '2019-01-24T13:53:52'),
('5', 'Normal Email', '2019-01-21T13:53:52'),
('6', 'Regular Email', '2019-01-14T13:53:52'),
('7', 'Regular Email', '2019-01-23T13:53:52'),
('8', 'Regular Email', '2019-01-23T13:53:52'),
('9', 'Regular Email', '2019-01-20T13:53:52'),
('10', 'Very Urgent Email', '2019-01-25T13:53:52'),
('11', 'Very Urgent Email', '2019-01-25T13:53:52');
INSERT INTO `Classification` (`id`, `mail_id`, `category_id`) VALUES
('1', '1', '1'),
('2', '2', '2'),
('3', '3', '2'),
('4', '4', '2'),
('5', '5', '3'),
('6', '6', '3'),
('7', '6', '3'),
('8', '6', '3'),
('9', '6', '3'),
('10', '6', '2'),
('11', '6', '2');
I want to return the number of mails received for each category for each date recorded, i.e. my expected results would be
+----------------------+-----------+----------+
| date | name | count(*) |
+----------------------+-----------+----------+
| 2019-01-04T13:53:52Z | Important | 1 |
| 2019-01-14T13:53:52Z | Normal | 1 |
| 2019-01-19T13:53:52Z | Urgent | 1 |
| 2019-01-20T13:53:52Z | Normal | 1 |
| 2019-01-21T13:53:52Z | Normal | 1 |
| 2019-01-23T13:53:52Z | Normal | 2 |
| 2019-01-24T13:53:52Z | Urgent | 1 |
| 2019-01-25T13:53:52Z | Urgent | 2 |
+----------------------+-----------+----------+
To do so I run the following query with a double groupby, filtering on the Classification table:
SELECT Mail.date, Category.name, count(*) FROM Mail, Classification, Category WHERE Category.id = Classification.category_id AND Classification.mail_id = Mail.id GROUP BY Mail.date, Category.name
Which gives me the following results:
+----------------------+-----------+----------+
| date | name | count(*) |
+----------------------+-----------+----------+
| 2019-01-04T13:53:52Z | Important | 1 |
| 2019-01-14T13:53:52Z | Normal | 4 |
| 2019-01-14T13:53:52Z | Urgent | 2 |
| 2019-01-19T13:53:52Z | Urgent | 1 |
| 2019-01-21T13:53:52Z | Normal | 1 |
| 2019-01-24T13:53:52Z | Urgent | 2 |
+----------------------+-----------+----------+
Which is entirely wrong.
I've tried substituting the WHERE statement for a JOIN:
SELECT Mail.date, Category.name, count(*) FROM (Mail, Category) RIGHT JOIN Classification ON Category.id = Classification.category_id AND Classification.mail_id = Mail.id GROUP BY Mail.date, Category.name `
But I get the exact same results as above.
Why are those queries returning these erroneous results and what should I do to fix them ?
First, your query should look like this:
SELECT m.date, c.name, count(*)
FROM Mail m JOIN
Classification cl
ON cl.mail_id = m.id JOIN
Category c
ON c.id = cl.category_id
GROUP BY m.date, c.name ;
Now that we have gotten that out of the way, your problem is that emails have multiple categories. So, they are multiply counted. Hence, the results you are getting are correct.
You have exact duplicates in the classification table, so a simple solution is:
SELECT m.date, c.name, count(distinct m.id)
FROM Mail m JOIN
Classification cl
ON cl.mail_id = m.id JOIN
Category c
ON c.id = cl.category_id
GROUP BY m.date, c.name ;
That said, the real solution is to fix your data, so it doesn't have duplicates.
Here is the SQL Fiddle using your data. You have a "2" for emails on 2019-01-23. However, there are no classified emails on that date, so they are not in the results.