Left join that will exclude certain rows - mysql

When I left join the following tables, I get the results for all the id's. I need to exclude the results where there is no single id present in sms table.
So the expected output is as follows:
+-----------+-----------+
| messageid | mobilenos |
+-----------+-----------+
| a | 12 |
| c | 31 |
+-----------+-----------+
2 rows in set (0.00 sec)
The messageid "d" should not be displayed in the output because there is not a single entry for "d" in the sms table.
I will like to know if the following query is correct or if there is a better way:
select a.* from splitvalues as a
left join sms as b on a.messageid = b.batchid and a.mobilenos = b.destination
left join (select a.messageid from splitvalues as a left join sms as b on a.messageid = b.batchid where b.batchid is null) as dt on dt.messageid = a.messageid where dt.messageid is null and b.destination is null;
Following are the table details:
splitvalues
messageid mobilenos
a 10
a 11
a 12
b 20
b 21
b 22
b 23
b 24
c 30
c 31
d 40
d 41
d 42
d 43
sms
batchid destination
a 10
a 11
b 20
b 21
b 22
b 23
b 24
c 30
drop table if exists splitvalues;
drop table if exists sms;
create table if not exists splitvalues (messageid varchar(255), mobilenos int);
create table if not exists sms (batchid varchar(255), destination int);
insert into splitvalues values ('a', 10), ('a', 11), ('a', 12), ('b', 20), ('b', 21), ('b', 22), ('b', 23), ('b', 24), ('c', 30), ('c', 31), ('d', 40), ('d', 41), ('d', 42), ('d', 43);
insert into sms values ('a', 10), ('a', 11), ('b', 20), ('b', 21), ('b', 22), ('b', 23), ('b', 24), ('c', 30);
mysql> select a.* from splitvalues as a left join sms as b on a.messageid = b.batchid and a.mobilenos = b.destination where b.destination is null;
+-----------+-----------+
| messageid | mobilenos |
+-----------+-----------+
| a | 12 |
| c | 31 |
| d | 40 |
| d | 41 |
| d | 42 |
| d | 43 |
+-----------+-----------+
6 rows in set (0.00 sec)

Try This...
select a.* from [dbo].[splitvalues] a join [dbo].[sms] b on a.messageid=b.batchid
Or
select a.* from [dbo].[splitvalues] a ,[dbo].[sms] b where a.messageid=b.batchid

Try inner join it will produce rows which exists in both table,
select * from splitvalues as a
inner join sms as b on a.messageid = b.batchid and a.mobilenos = b.destination

select * from
splitvalues
where mobilenos not in(select destination from sms) limit 2;

Related

How to count duplication items?

Every customer should not have duplicated code, as you can see the result below for example Customer-A have duplicated Code of 22 and Customer-D have duplicated Code of 44
I like to run a query to get a number of how many duplications do we have, from the result below it should be 4. I have tried using Group By Code and Having but not having much luck.
customer Code
------ ---------
A 11
A 22
A 22
B 33
C 22
D 44
D 44
D 44
D 22
We can use group by and keep the combinations with more than one line
create table t(
customer char(1),
Code int);
insert into t values
('A', 11),
('A', 22),
('A', 22),
('B', 33),
('C', 22),
('D', 44),
('D', 44),
('D', 44),
('D', 22);
SELECT
customer,
code,
count(*) "number"
FROM t
GROUP BY
customer,
code
HAVING
COUNT(*) > 1;
customer | code | number
:------- | ---: | -----:
A | 22 | 2
D | 44 | 3
db<>fiddle here

Combine rows/columns from two tables - JOIN clause

In the link see my SQLFIDDLE and see b
CREATE TABLE Projects
(`p_id` int, `project_title` varchar(9), `l_id` int);
INSERT INTO Projects
(`p_id`, `project_title`, `l_id`)
VALUES
(1, 'A', 6),
(2, 'B', 6),
(3, 'C', 7),
(4, 'D', 8),
(5, 'E', 9),
(6, 'F', 10);
CREATE TABLE Locations
(`l_id` int, `title` varchar(9), `parent_id` int );
INSERT INTO Locations
(`l_id`, `title`, `parent_id`)
VALUES
(1, 'Country', 0),
(2, 'District1', 1),
(3, 'District2', 1),
(4, 'District3', 1),
(5, 'District4', 1),
(6, 'Loc 5', 2),
(7, 'Loc 6', 3),
(8, 'Loc 7', 3),
(9, 'Loc 8', 4),
(10, 'Loc 9', 4),
(11, 'Loc 10', 4),
(12, 'Loc 11', 5);
I would like to achieve this:
+------+-----------+-------------+
| L_ID | Title | count P_ID |
+------+-----------+-------------+
| 2 | District1 | 2 |
| 3 | District2 | 2 |
| 4 | District3 | 2 |
| 5 | District4 | 0 |
+----+------------+------+-------+
I have tried with INNER JOIN, LEFT OUTER JOIN. All i can achieve is like below and doesnt help me:
+------+-----------+----------------------+
| L_ID | Title | parent_id | counted |
+------+-----------+------------+---------+
| 6 | Loc 5 | 2 | 2 |
| 7 | Loc 6 | 3 | 2 |
| 9 | Loc 8 | 4 | 2 |
+---- -+-----------+------------+---------+
Locations table is a nested one, if this matters. I need to count projects that are in each District and also to get District name.
I tried:
SELECT l.*, COUNT(p.l_id) AS thecounted
FROM locations l
INNER JOIN projects p ON p.l_id = l.l_id
GROUP BY l.parent_id
and
SELECT l.*, COUNT(p.l_id) AS thecounted
FROM locations l
LEFT OUTER JOIN projects p on l.l_id = p.l_id
GROUP BY l.parent_id
Consider two joins:
select d.l_id, d.title, count(p.l_id) count_p_id
from locations d
left join locations l on l.parent_id = d.l_id
left join projects p on p.l_id = l.l_id
where d.parent_id = 0
group by d.l_id, d.title
The query starts from the list of districts (d), whose parent is 0. Then, it goes down one level to the locations (l), and looks up the corresponding projects (p). The final step is aggregation.
The solution of GMB returns this 1 row
l_id title count_p_id
1 Country 0
using this script version
select d.l_id, d.title, count(p.l_id) count_p_id
from locations d
left join locations l on l.parent_id = d.l_id
left join projects p on p.l_id = l.l_id
where d.parent_id = 0
group by d.l_id, d.title
We get the desired result with the slightly corrected condition
where d.parent_id = 1
Result:
l_id title count_p_id
2 District1 2
3 District2 2
4 District3 2
5 District4 0
Sorry for posting the answer, instead of a simple comment, which would be sufficient, but don't have enough reputation credits yet.

SQL - get distinct values and its frequency count of occurring in a group

I have a table data as:
CREATE TABLE SERP (
id INT(6) UNSIGNED AUTO_INCREMENT PRIMARY KEY,
s_product_id INT,
search_product_result VARCHAR(255)
);
INSERT INTO SERP(s_product_id, search_product_result)
VALUES
(0, 'A'),
(0, 'B'),
(0, 'C'),
(0, 'D'),
(1, 'A'),
(1, 'E'),
(2, 'A'),
(2, 'B'),
(3, 'D'),
(3, 'E'),
(3, 'D');
The data set is as follows:
s_product_id | search_product_result
___________________________________________
0 | A
0 | B
0 | C
0 | D
-------------------------------------------
1 | A
1 | E
-------------------------------------------
2 | A
2 | B
-------------------------------------------
3 | D
3 | E
3 | D
I need to list all distinct search_product_result values and count frequencies of these values occurring in s_product_id.
Required Output result-set:
DISTINCT_SEARCH_PRODUCT | s_product_id_frequency_count
------------------------------------------------------------
A | 3
B | 2
C | 1
D | 2 [occurred twice in 3, but counted only once.]
E | 2
Here, A occurs in three s_product_id : 0, 1, 2, B in two : 0, 2, and so on.
D occurred twice in the same group 3, but is counted only once for that group.
I tried grouping by search_product_result, but this counts D twice in the same group.
select search_product_result, count(*) as Total from serp group by search_product_result
Output:
search_product_result | Total
------------------------------------
A | 3
B | 2
C | 1
D | 3 <---
B | 2
You can try below - use count(distinct s_product_id)
select search_product_result, count(distinct s_product_id) as Total
from serp group by search_product_result
use count(distinct()
select search_product_result, count(distinct s_product_id, search_product_result) as Total
from SERP
group by search_product_result
see dbfiddle

Update a table with conditions in specfic order

I have searched the web for my problem, tested some subqueries and derived table approaches with Case Statements, but didnĀ“t get the result. Perhaps you can help? Thanks.
The examples below are just an example.
# generate the table as it is
DROP TABLE IF EXISTS `IN`;
CREATE TABLE `IN`
(`Part` CHAR(1),
`Warehouse` INT(1),
`Percentage` INT(1),
`Update` INT(1));
#some values for the table
INSERT INTO `IN`
(Part, Warehouse, Percentage)
VALUES
('A' , 1, 80),
('A', 2, 100),
('A', 3, 50),
('B', 1, 100),
('B', 2, 50),
('B', 3, 100);
# generate table as it should be
DROP TABLE IF EXISTS `OUT`;
CREATE TABLE `OUT`
(`Part` CHAR(1),
`Warehouse` INT(1),
`Percentage` INT(1),
`Update` INT(1));
# values for the table
INSERT INTO `OUT`
(Part, Warehouse, Percentage, `Update`)
VALUES
('A' , 1, 80, 2),
('A', 2, 100, 2),
('A', 3, 50, 2),
('B', 1, 100, 3),
('B', 2, 50, 3),
('B', 3, 100, 3);
I would like to add the specific warehouse name in the column Update for the specific part if the percentage is 100.
The value of the warehouse should be filled to every row for the specific part.
The fill calculation of the update column should be in a specific order.
So first there should be a check if warehouse 3 has 100 and take this value. If warehouse 3 only has 50 then check warehouse 2, if it has 100.
Thank you very much!
Here's one way...
DROP TABLE IF EXISTS my_table;
CREATE TABLE my_table
(Part CHAR(1)
,Warehouse INT NOT NULL
,Percentage TINYINT NOT NULL
);
INSERT INTO my_table
(Part, Warehouse, Percentage)
VALUES
('A' , 1, 80),
('A', 2, 100),
('A', 3, 50),
('B', 1, 100),
('B', 2, 50),
('B', 3, 100);
SELECT w1.*, COALESCE(w3.warehouse,w2.warehouse,w1.warehouse) warehouse
FROM my_table w1
LEFT
JOIN my_table w2
ON w2.part = w1.part
AND w2.warehouse = 2
AND w2.percentage = 100
LEFT
JOIN my_table w3
ON w3.part = w1.part
AND w3.warehouse = 3
AND w3.percentage = 100;
+------+-----------+------------+-----------+
| Part | Warehouse | Percentage | warehouse |
+------+-----------+------------+-----------+
| A | 1 | 80 | 2 |
| A | 2 | 100 | 2 |
| A | 3 | 50 | 2 |
| B | 1 | 100 | 3 |
| B | 2 | 50 | 3 |
| B | 3 | 100 | 3 |
+------+-----------+------------+-----------+

Why is the result of sum doubled in this simple query?

mysql> create table a (
-> id varchar(10),
-> val int
-> );
Query OK, 0 rows affected (0.02 sec)
mysql> create table b (
-> id varchar(10),
-> val int
-> );
Query OK, 0 rows affected (0.02 sec)
mysql> insert into a values ('a', 1), ('b', 2), ('c', 3);
mysql> insert into b values ('a', 4), ('a', 5), ('b', 6), ('b', 7), ('c', 8), ('c', 9);
mysql> select a.id, sum(a.val), sum(b.val) from a inner join b on a.id = b.id group by a.id;
+------+------------+------------+
| id | sum(a.val) | sum(b.val) |
+------+------------+------------+
| a | 2 | 9 |
| b | 4 | 13 |
| c | 6 | 17 |
+------+------------+------------+
3 rows in set (0.00 sec)
My expected result was for sum(a.val) to present 1, 2 and 3, sum(b.val) to present 9, 13 and 17.
How should I rewrite the query to get the expected result?
It is due to the JOIN with the other table.
If you just run the simple query with the JOINS but without the SUM, you will see that the records in Table A are being doubled, because you INNER JOIN with TABLE B.
A.ID A.val B.val
a 1 4
a 1 5
b 2 6
b 2 7
c 3 8
c 3 9
In order to get the expected result, you will have to query like this:
SELECT
A.ID,
A.VAL 'A Sum',
B.VAL 'B Sum'
FROM
(SELECT ID, SUM(VAL) AS 'VAL' FROM A GROUP BY ID) A INNER JOIN
(SELECT ID, SUM(VAL) AS 'VAL' FROM B GROUP BY ID) B ON A.ID = B.ID
Here is a SQLFiddle with how this query works.
Here is the result of the join query before doing the group by and sum:
a.id a.val b.val
---- ----- -----
a 1 4
a 1 5
b 2 6
b 2 7
c 3 8
c 3 9
As you see here, the sum(a.val) for all rows with a.id='a' will give you 2 since there are 2 rows. So the results, are [2, 4, 6], not [1, 2, 3].