Find rows without corresponding second row in MySQL - mysql

Given the following table:
type | area | shelf
-----|------|------
1 | a | 5
2 | a | 5
2 | a | 6
1 | a | 7
2 | a | 7
1 | b | 3
An area / shelf combination entry with type 2 always needs a corresponding entry with type 1. Type 1 can exist on its own (e.g. last row).
How can I find orphan type 2 rows (rows with type 2 without corresponding row with type 1) such as the third row?

You can do this with aggregation and a having clause:
select shelf, area
from t
group by shelf, area
having sum(type = 2) > 0 and -- at least one type 2
sum(type = 1) = 0; -- no type 1

Are you looking for this..
SELECT t2.*
FROM yourtable t1
RIGHT JOIN yourtable t2 ON t1.area = t2.area
AND t1.shelf=t2.shelf
AND t1.`type`=1
AND t2.`type`=2
WHERE t1.`type` IS NULL

Related

MySQL - select distinct value from two column

I have a table with the following structure:
IdM|IdS
-------
1 | 2
1 | 3
1 | 4
2 | 1
2 | 3
2 | 4
3 | 1
3 | 2
3 | 3
3 | 4
How could I make a select statement on this table, which will return some rows of this table, where in each row, a specific id appears only one, indifferent on which column it is specified?
For the above result set, I would like a query that would return:
-------
1 | 2
3 | 4
-------
To give another example, if you would omit the first row in the original dataset:
IdM|IdS
-------
1 | 3
1 | 4
2 | 1
2 | 3
2 | 4
3 | 1
3 | 2
3 | 3
3 | 4
the result set should be:
-------
1 | 3
2 | 4
-------
That's actually an interesting problem. If I follow you correctly, you want to iterate through the dataset and only retain rows where both values were never seen before. You could use a recursive query:
with recursive
data as (
select idm, ids, row_number() over(order by idm, ids) rn
from mytable
where idm <> ids
),
cte as (
select idm, ids, rn, 1 as to_keep , concat(idm, ',', ids) visited from data where rn = 1
union all
select d.idm, d.ids, d.rn,
(not find_in_set(d.idm, c.visited) and not find_in_set(d.ids, c.visited)),
case when (not find_in_set(d.idm, c.visited) and not find_in_set(d.ids, c.visited))
then concat_ws(',', c.visited, d.idm, d.ids)
else c.visited
end
from cte c
inner join data d on d.rn = c.rn + 1
)
select idm, ids from cte where to_keep
The first CTE enumerates the rows ordered by both columns. Then the recursive query walks the resultset, checks if both values are new, and sets a flag accordingly of the columns. Flagged numbers are retained to be used for filtering in the following iteration.
Demo on DB Fiddle
Note that, given your requirement, not all values may appear in the resultset. Consider the following dataset:
idm ids
+-----+---
1 2
1 3
1 4
Your logic will only return the first row.

Selecting one distinct row from group of entries

ID TYPE DATE
1 A 01/02/2019
1 B 01/21/2019
1 C 02/03/2019
2 A 01/04/2019
2 C 01/29/2019
3 A 01/14/2019
3 B 03/11/2019
So using the table above as an example what I'm trying to do with a similar table is extract a specific Type from each Distinct ID. So let's say I only want to Select Type B from each Distinct ID. Now, the big confusion starts for me when I incorporate the Date. I want to Select Type B from each ID but only if Type B is the most recent date.
So in this instance the only row with Type B as the last date would be the last row.
3 B 03/11/2019
Any suggestions as to what my query should look like?
With NOT EXISTS:
select t.* from tablename t
where t.type = 'B'
and not exists (
select 1 from tablename
where id = t.id and date > t.date
)
See the demo.
Results:
| ID | TYPE | DATE |
| --- | ---- | ------------------- |
| 3 | B | 2019-03-11 00:00:00 |

Loop unique insert into temporary table MySql stored procedure

I have two tables that look like this:
Table 1
Type 1 | Type 2 | Type 3 | ...
1 | 3 | 0 | ...
Table 2
Type 1 | Type 2 | Type 3 | ...
3 | 2 | 1 | ...
I would like to combine them into a temporary table like this:
Temporary Table
UID | Type | Table
1 | Type 1 | 1
2 | Type 2 | 1
3 | Type 2 | 1
4 | Type 2 | 1
7 | Type 1 | 2
8 | Type 1 | 2
9 | Type 1 | 2
10 | Type 2 | 2
11 | Type 2 | 2
Essentially, the numbers in tables 1 and 2 are totals and I want to break them out into individual rows in this temporary table.
I started going down the path of selecting from both tables and storing the values into temporary variables. I was then going to loop through every single variable and insert into the temporary table. But I have about 15 columns per table and there has got to be an easier way of doing this. I just don't know what it is.
Does anyone have any insight on this? My knowledge is incredibly limited on MySql stored procedures.
Not sure of an easy way to do this. One option would be to have a numbers table. Heres a quick approach to getting 1-10 in a common-table-expression (change as needed).
Then you could join to each table and each type, using union all for each subset. Here is a condensed version:
with numbers as (select 1 n union all select 2 union all
select 3 union all select 4 union all select 5 union all
select 6 union all select 7 union all select 8 union all
select 9 union all select 10)
select 'type1' as type, '1' as tab
from numbers n join table1 t on n.n <= t.type1
union all
select 'type2' as type, '1' as tab
from numbers n join table1 t on n.n <= t.type2
union all
select 'type1' as type, '2' as tab
from numbers n join table2 t on n.n <= t.type1
union all
select 'type2' as type, '2' as tab
from numbers n join table2 t on n.n <= t.type2
Demo Fiddle

Show single set of results from two tables

I am trying to show the results of items from one table where the count from another table equals a number from the first. I have been stuck on how to go about doing this for a couple weeks now so iv finally decided to ask for help. Im having a hard time explaining exactly what it is i need but i will try my best.
I am using PDO to interact with my database which is mysql.
For instance i have two tables:
table 1
-----------------
key | name | total
1 | item 1 | 3
2 | item 2 | 4
3 | item 3 | 2
table 2
-----------------
key | table1 key
1 | 1
2 | 2
3 | 3
4 | 1
5 | 1
6 | 3
7 | 2
8 | 2
So in this case there would be 3/3 items for item 1, 3/4 items for item 2, and 2/2 items for item 3. So it would show item 1 and item 3 as a result because the count for those two equal the total from table one.
I hope I explained this well enough.
If you want a sql query to do that, try this:
select t1.*
from table1 t1
inner join (
select table1_key, count(1) as cnt from table2 group by table1_key
) t2 on t1.key = t2.table1_key and t1.total = t2.cnt
SQLFiddel Demo

Finding cooccuring values in MYSQL weak relation table

I have a weak relation table, called header, it is basically just three ID's: id is an autoincrement primary key, did points to the id of table D and hid points to the id of table H. D and H are irrelevant here.
I want to find for any value of hid, the other values of hid that shares did with the original hid. An example:
id | did | hid
===============
1 | 1 | 1
2 | 1 | 2
3 | 1 | 3
4 | 2 | 1
5 | 2 | 4
6 | 2 | 5
7 | 3 | 2
8 | 3 | 6
For hid = 1 I would thus like to find id = {2,3,5,6} as those are the rows that have did in common with hid = 1.
I can do this by creating some arrays in PHP and running through all possible values of hid and respective did, but this is a quite slow process for large tables. I was wondering if there is a clever kind of JOIN or similar statement that could be used to find the cooccuring values of hid.
If I have understood you correctly:-
SELECT a.hid, GROUP_CONCAT(b.id)
FROM header a
INNER JOIN header b
ON a.did = b.did
AND b.hid != 1
WHERE a.hid = 1
GROUP BY a.hid
SQL fiddle:-
http://www.sqlfiddle.com/#!2/9aa26/1
Maybe this:
SELECT d.id
FROM (
SELECT *
FROM header
WHERE header.hid =1
) AS h
JOIN header AS d ON d.did = h.did
WHERE d.hid !=1