I have this MySQL table :
create table example (
My_Id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
My_Integer INT UNSIGNED DEFAULT 0
) ENGINE=InnoDB
Suppose this table to be populated like that :
SELECT * FROM `example`
My_Id My_Integer
1 10
2 1
3 3
4 152
5 16
6 481
7 128
My goal is to retrieve, from an user input, which integer is not in my table 'example'.
For example, if the user enter 1, 3, 10, the result should be empty.
If the user enter 1, 2, 3, 10, the result should be "2".
I can't find a way to do that, other than to do one MySQL request per integer in order to know if the number is in the table 'example'.
Do someone know a way ?
Select numberToMatch
from example as a
right outer join (
select 1 as numberToMatch union all
select 2 union all
select 3 union all
select 10
) as b
on b.numberToMatch = a.My_Integer
where a.My_Integer is null
Using right outer join and select those null record in the left table.
You could genereate tally table and use OUTER JOIN:
SELECT t.n
FROM (
SELECT a.N + b.N * 10 + c.N * 100 + 1 n
FROM (SELECT 0 AS N UNION ALL SELECT 1 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) a
,(SELECT 0 AS N UNION ALL SELECT 1 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) b
,(SELECT 0 AS N UNION ALL SELECT 1 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) c
) t
LEFT JOIN example e
ON t.n = e.My_Integer
WHERE t.n IN (1,2,3,10) -- here goes numbers
AND e.My_Integer IS NULL;
LiveDemo
Output:
╔═══╗
║ n ║
╠═══╣
║ 2 ║
╚═══╝
It will work in range 1-999. You could expand it if needed.
Another way is to use UNION ALL:
SELECT s.col
FROM (SELECT 1 AS col
UNION ALL SELECT 2
UNION ALL SELECT 3
UNION ALL SELECT 10) AS s
LEFT JOIN example e
ON s.col = e.My_Integer
WHERE e.My_Integer IS NULL;
LiveDemo2
Related
Table: Sequence
id
1
3
7
9
11
13
What I tried is :
select l.id + 1 as start
from sequence as l
left outer join sequence as r on l.id + 1 = r.id
where r.id is NULL;
This does not capture all required numbers but only the +1s from the number available in the initial table.
My required output is :
2
4
5
6
8
10
12
Using a calendar table approach:
WITH nums AS (
SELECT 1 AS id 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 UNION ALL SELECT 11 UNION ALL SELECT 12 UNION ALL
SELECT 13 UNION ALL SELECT 14 UNION ALL SELECT 15
)
SELECT n.id
FROM nums n
LEFT JOIN Sequence s
ON s.id = n.id
WHERE
s.id IS NULL;
On earlier versions of MySQL, which don't support CTE, you may either create a bona fide nums sequence table, or just inline the CTE:
SELECT n.id
FROM (
SELECT 1 AS id 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 UNION ALL SELECT 11 UNION ALL SELECT 12 UNION ALL
SELECT 13 UNION ALL SELECT 14 UNION ALL SELECT 15
) n
LEFT JOIN Sequence s
ON s.id = n.id
WHERE
s.id IS NULL;
Users table has id field in mysql database, and table has below record in id field
|id|
2
3
5
6
9
10
15
16
18
21
25
I want to get missing records row like below:-
1
4
7
8
11
12
13
14
17
19
20
22
23
24
How cool is this ?
SELECT seq.`id` FROM (
SELECT #row := #row + 1 as `id`
FROM `users` t, (SELECT #row := 0) r
CROSS JOIN `users` t2
) as seq WHERE seq.`id` NOT IN (SELECT `id` FROM `users`)
AND seq.`id` <= (SELECT max(`id`) from `users`);
If you want the missing ids for analytical purpose, should love this one:
SELECT CONCAT(dt.missing, IF(dt.`found`-1 > dt.missing, CONCAT(' to ', dt.`found` - 1), '')) AS missing
FROM ( SELECT #rownum:=#rownum+1 AS `missing`,
IF (#rownum=id, 0, #rownum:=id) AS `found`
FROM ( SELECT #rownum:=0 ) AS r
JOIN users
ORDER BY id ) AS dt
WHERE dt.`found`!= 0;
Use a calendar table approach and anti-join approach:
CREATE TABLE nums (id INT);
INSERT INTO nums (id)
(
SELECT (t*10+u+1) x FROM
(SELECT 0 t UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION
SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) A,
(SELECT 0 u UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION
SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) B
);
SELECT
n.id
FROM nums n
LEFT JOIN users u
ON n.id = u.id
WHERE
u.id IS NULL
ORDER BY
n.id;
Demo
Note that in the demo and query I did not limit the height of the range of missing numbers which gets returned. I arbitrarily used a sequence of numbers 1..100, but you may restrict to any size you want.
My next database table will be set up more optimally. Unfortunately this one was already set up where one column [data] contains checkbox array values that were saved the following way:
value 1|~|value 1 value 2|~|value 2 value 3|~|value 3
Not optimal, I know.
What I need is a mysql query that select only the values in [data] column in front of the |~|. Basically think I need to select the only odd values.
Any help pointing me in the right direction is greatly appreciated. I tried an if statement in a query and it did not work. Of course I deleted that by mistake.
What I need is a mysql query that select only the
values in [data] column in front of the |~|.
One thing to note the numbers before |~| must be unique.
It will not show the same number twice.
Query
SELECT
DISTINCT
SUBSTRING (
record_data.column
, LOCATE('|~|', record_data.`column` , number_generator.number) - 1
, 1
) AS number
FROM (
SELECT
#row := #row + 1 AS number
FROM (
SELECT 0 UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9
) record_1
CROSS JOIN (
SELECT 0 UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9
) record_2
CROSS JOIN (
SELECT 0 UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9
) record_4
CROSS JOIN (
SELECT 0 UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9
) record_5
CROSS JOIN (
SELECT #row := 0
) AS init_user_params
) AS number_generator
CROSS JOIN (
SELECT
*
FROM (
SELECT 'value 1|~|value 1 value 2|~|value 2 value 3|~|value 3' AS `column`
) AS record
) AS record_data
WHERE
LOCATE('|~|', record_data.`column` , number_generator.number) <> 0
Result
| number |
| ------ |
| 1 |
| 2 |
| 3 |
demo
SELECT ID FROM TABLE WHERE ID BETWEEN 1 AND 5
The result of the query above will be: 1,2,3,4,5
If only id 1 and id 2 who are exist in the table, then it will loop (1,2) only.
It means, if the id is between 1 AND 5, the id of 3,4,5 doesn't exist.
the id of 3,4,5 is what I want to select. How to do this?
Thanks in advance.
Try this:
select * from
(
select 1 as val
union all
select 2
union all
select 3
union all
select 4
union all
select 5
)t
left join TableName tn on t.val = tn.id
where tn.id is null
With tally table:
select * from (
select (3 + th*1000+h*100+t*10+u+1) x from
(select 0 th union select 1 union select 2 union select 3 union select 4 union
select 5 union select 6 union select 7 union select 8 union select 9) A,
(select 0 h union select 1 union select 2 union select 3 union select 4 union
select 5 union select 6 union select 7 union select 8 union select 9) B,
(select 0 t union select 1 union select 2 union select 3 union select 4 union
select 5 union select 6 union select 7 union select 8 union select 9) C,
(select 0 u union select 1 union select 2 union select 3 union select 4 union
select 5 union select 6 union select 7 union select 8 union select 9) D)
tn
left join t on tn.x = t.id
where tn.x between 3 and 10
and t.id is null
Notice in formula (3 + th*1000+h*100+t*10+u+1) and where clause 3 is srart, 10 is end. Change on variables.
Here is fiddle: http://sqlfiddle.com/#!9/2f53f/2
Mainly, I would like to insert a row in table 1 multiple times, based on an integer value in a column of table 2.
My situation
Table 2 contains a column 'SKU' and 'stock', and I would like to insert the 'SKU' and a timestamp into table 1. I want this row duplicated for 'stock'-value times in table 1.
I currently have the following query:
DECLARE #Count int = 1
WHILE #Count <= ....
BEGIN
INSERT INTO table1 (table1.SKU, table1.timestamp_in)
SELECT table2.SKU, "some timestamp" FROM table2
SET ...
END
I am not sure if this is the correct approach. I would like to run this loop for 'table2.stock' times.
My question is: Is this possible with just a SQL query, or should it be a better practice to build some (in my case) java code for this?
You don't need a procedure or anything like that. All you need is a table containing just numbers. I'm creating this table on the fly with this in this example:
SELECT aa.a + 10*bb.b + 100*cc.c AS numbers FROM (
SELECT 0 a UNION ALL SELECT 1 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) aa
, (SELECT 0 b UNION ALL SELECT 1 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) bb
, (SELECT 0 c UNION ALL SELECT 1 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) cc;
This creates the numbers 0 till 999.
Now you join your table2 with this numbers table in the range of stock. Your final query looks like this:
INSERT INTO table1 (table1.SKU, table1.timestamp_in)
SELECT table2.SKU, "some timestamp" FROM table2
INNER JOIN (
SELECT aa.a + 10*bb.b + 100*cc.c AS n FROM (
SELECT 0 a UNION ALL SELECT 1 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) aa
, (SELECT 0 b UNION ALL SELECT 1 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) bb
, (SELECT 0 c UNION ALL SELECT 1 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) cc
) numbers ON numbers.n BETWEEN 0 AND table2.stock /*assuming you have no negative stock*/
Just make sure, that the numbers table contains more numbers than the highest value in the stock column.