MySQL Query that return "not exists value" - mysql

I want to know is it possible to do if I have 4 number as below
1,2,3,4
In my data base have data exists as below
1,2,3,5,6,7
How can I query database and return 4 in 1 query
Please advise

CREATE TABLE `example` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`id`)
) ENGINE=InnoDB;
INSERT INTO example VALUES (1),(2),(3),(5),(6),(7);
SELECT t2.id FROM example AS t1
RIGHT JOIN (
SELECT 1 AS id UNION
SELECT 2 AS id UNION
SELECT 3 AS id UNION
SELECT 4 AS id
) AS t2
ON t1.id = t2.id
WHERE t1.id IS NULL;
+----+
| id |
+----+
| 4 |
+----+
Or use a temporary table:
CREATE TEMPORARY TABLE `tmp` (
`id` int(11) DEFAULT NULL
) ENGINE=InnoDB;
INSERT INTO tmp VALUES (4);
SELECT t2.id FROM example AS t1
RIGHT JOIN tmp AS t2
ON t1.id = t2.id
WHERE t1.id IS NULL;
To see what's happening, switch things around a bit:
SELECT t1.id, t2.id FROM example AS t1
RIGHT JOIN (
SELECT 1 AS id UNION
SELECT 2 AS id UNION
SELECT 3 AS id UNION
SELECT 4 AS id
) AS t2
ON t1.id = t2.id;
+------+----+
| id | id |
+------+----+
| 1 | 1 |
| 2 | 2 |
| 3 | 3 |
| NULL | 4 |
+------+----+

SELECT id FROM
( SELECT 1 AS id UNION
SELECT 2 UNION
SELECT 3 UNION
SELECT 4
) AS TBL1
WHERE id NOT IN (SELECT id FROM thetable)

Related

Get all parents of multiple objects in same table

for an mass edit function I need to load the parents of multiple objects.
Doing this with single querys would kill the db. I'm using MySQL 5.7 My table is build like this:
CREATE TABLE `testtable` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`content` text,
`parentid` bigint(20) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8
INSERT INTO testtable(`id`, `content`, `parentid`)
VALUES(1, 'parentA1', 0),(5, 'parentA2', 1),(3, 'childA', 2),
(4, 'parentB', 0),(5, 'childB', 4);
For single object querys I use this statement to get all parents:
SELECT t.id, t.content, #pid := t.parentid AS parentid
FROM (SELECT * FROM Table1 order by id DESC) t
JOIN (SELECT #pid := 3) tmp
WHERE t.id = #pid
But I have absolutly no clue how this could work for multiple object at once without using union.
My whised ouput should look like this:
id | content | parentid | searchingChildID
1 | parentA1| 0 | 3
2 | parentA2| 1 | 3
3 | childA | 2 | 3
4 | parentB | 0 | 5
5 | childB | 4 | 5
Thanks in advance!
If you are running MySQL 8.0, this is a typical use case for a recursive query. Say you want all parents of objects 3 and 4, you can do:
with recursive cte as (
select t.id as originalid, t.* from table1 where id in (3, 4)
union all
select c.originalid, t.*
from cte c
inner join table1 t on t.id = c.parentid
)
select * from cte
for an mass edit function I need to load the parents of multiple objects.
For this operation, I would expect:
id | content | parentid | ultimateparent
1 | parentA1| 0 | 0
2 | parentA2| 1 | 0
3 | childA | 2 | 0
4 | parentB | 0 | 0
5 | childB | 4 | 0
Because 0 is the ultimate parent of all the rows. If you know the maximum depth, you can use left joins in pre-8 versions of MySQL:
select t1.*, coalesce(t3.parentid, t2.parentid, t1.parentid) as ultimateparent
from testtable t1 left join
testtable t2
on t2.id = t1.parentid left join
testtable t3
on t3.id = t2.parentid
You can trivially extend this with more left joins to handle deeper levels of parentage.
If 0 really means "no parent" (which is an odd choice when NULL is available) then you would seem to want:
id | content | parentid | ultimateparent
1 | parentA1| 0 | 1
2 | parentA2| 1 | 1
3 | childA | 2 | 1
4 | parentB | 0 | 4
5 | childB | 4 | 4
Then you can actually just tweak the above query to:
select t1.*, coalesce(t3.id, t2.id, t1.id) as ultimateparent
from testtable t1 left join
testtable t2
on t2.id = t1.parentid left join
testtable t3
on t3.id = t2.parentid;
Here is a db<>fiddle.
You can get the maximum child for each parent as well (although that seems quite arbitrary). In pre-8.0 versions of MySQL, variables are the simplest approach:
select t1.*,
(#max_child := if(#up = ultimateparent, #max_child,
if(#up := ultimateparent, id, id)
)
) as max_childid
from (select t1.*, coalesce(t3.id, t2.id, t1.id) as ultimateparent
from testtable t1 left join
testtable t2
on t2.id = t1.parentid left join
testtable t3
on t3.id = t2.parentid
order by ultimateparent, id desc
) t1 cross join
(select #up := -1, #max_child := -1) params;

I need the records which doesn't matches in both tables

I need those records in a table list which doesn't link to table t1 to table t2
I have tried inner join. I need the records without subquery
CREATE TABLE t1 (
id INT PRIMARY KEY
);
CREATE TABLE t2 LIKE t1;
INSERT INTO t1(id) VALUES(1),(2),(3);
INSERT INTO t2(id) VALUES(2),(3),(4);
mysql> select * from t1;
+----+
| id |
+----+
| 1 |
| 2 |
| 3 |
+----+
3 rows in set (0.01 sec)
mysql> select * from t2;
+----+
| id |
+----+
| 2 |
| 3 |
| 4 |
+----+
3 rows in set (0.00 sec)
I need :
+----+
| id |
+----+
| 1 |
| 4 |
+----+
you could try left join on the union of the id and check for null
select t3.id
from (
select t1.id from t1
union
select t2.id from t2
) t3
left join t1 on t1.id = t3.id
left join t2. on t2.id = t3.id
where t2.id is null
or t1.id is null
select * from t1 where not exists (select * from t2 where t1.id = t2.id)
or
select * from t1 where id not in (select id from t2)
and likewise for t2. Union them together if you want them in a single result set.
Update: subquery-less version:
select coalesce(t1.id, t2.id) from t1 full outer join t2 on (t1.id = t2.id)
where t1.id is null or t2.id is null

SQL merge result of two queries

Both queries use the same table (here: test)
First query:
SELECT `test` as t1, COUNT( * ) as t2
FROM `test_table`
WHERE `test` > 5
GROUP BY `test`
returns result in form
--------------------------------------------------
| t1 | t2 |
--------------------------------------------------
| 6 | 2 |
--------------------------------------------------
| 8 | 7 |
--------------------------------------------------
Second query:
SELECT TRUNCATE(((num1/num2) * 100),3) as t3
FROM
(SELECT COUNT( * ) as num1
FROM `test_table`
WHERE test > 5
group by `test`) a,
(SELECT COUNT( * ) as num2
FROM `test_table`
WHERE test > 5) b
returns result in form
--------------------------------------------------
| t3 |
--------------------------------------------------
| 40.456% |
--------------------------------------------------
| 59.544% |
--------------------------------------------------
What I would like to have is:
--------------------------------------------------
| t1 | t2 | t3 |
--------------------------------------------------
| 6 | 2 | 40.456% |
--------------------------------------------------
| 8 | 7 | 59.544% |
--------------------------------------------------
How can I do it ? Union puts the t3 results below t1 t2, perhaps join statement ? But join on what ? Or can I make a one query from these two which selects all the data?
Using subquery in the select makes it quite readable
DROP TABLE IF EXISTS TEST_TABLE;
CREATE TABLE TEST_TABLE(TEST INT);
INSERT INTO TEST_TABLE VALUES
(6),(6),
(8),(8),(8),(8),(8),(8),(8);
SELECT `test` as t1, COUNT(*) as t2,
TRUNCATE(COUNT(*) / (SELECT COUNT(*) FROM TEST_TABLE WHERE TEST > 5) * 100,3) AS T3
FROM `test_table`
WHERE `test` > 5
GROUP BY `test`
Result
+------+----+--------+
| t1 | t2 | T3 |
+------+----+--------+
| 6 | 2 | 22.222 |
| 8 | 7 | 77.777 |
+------+----+--------+
2 rows in set (0.00 sec)
This can be done with a few modifications of your second query:
SELECT a.t1, num1 as t2, TRUNCATE(((num1/num2) * 100),3) as t3
FROM
(SELECT `test` as t1, COUNT( * ) as num1
FROM `test_table`
WHERE test > 5
group by `test`) a,
(SELECT COUNT( * ) as num2
FROM `test_table`
WHERE test > 5) b
SELECT
Z.t1, Z.t2, Z1.t3
FROM
(SELECT
`test` AS t1, COUNT(*) AS t2
FROM
`test_table`
WHERE
`test` > 5
GROUP BY `test`) Z
INNER JOIN
(SELECT
t1, TRUNCATE(((num1 / num2) * 100), 3) AS t3
FROM
(SELECT
test t1, COUNT(*) AS num1
FROM
`test_table`
WHERE
test > 5
GROUP BY `test`) a, (SELECT
COUNT(*) AS num2
FROM
`test_table`
WHERE
test > 5) b) Z1 ON Z.t1 = Z1.t1;
Try above code.
Hope this will help you.
The way it is structured in your example you should be able to join them on test_table.test (the Field you are using Group By on)

Fill blank in table with data from previous row SQL

I have a table with various null fields.
ID Value
1 A
2
3
4 B
5
Need to transform it to this output table:
ID Value
1 A
2 A
3 A
4 B
5 B
Requirement:
Preview the table before updating. Hence, a select statement with returns the above mentioned output table.
An update query which updates the first table to second table.
Unable to find any select query which shows the table in required format. Any help will be appreciated. Thanks.
A mysql query that uses a variable to keep track of the most recent non-null value
SELECT t1.id,
(CASE WHEN Value IS NULL
THEN #prevValue
ELSE #prevValue := Value END) Value
FROM myValues t1
CROSS JOIN (SELECT #prevValue := NULL) t2
ORDER BY t1.id
DROP TABLE IF EXISTS my_table;
CREATE TABLE my_table
(id INT NOT NULL AUTO_INCREMENT PRIMARY KEY
,value CHAR(1) NULL
);
INSERT INTO my_table VALUES
(1,'A'),
(2,NULL),
(3,NULL),
(4,'B'),
(5,NULL);
SELECT x.*
, MAX(y.value)
FROM my_table x
JOIN my_table y
ON y.value IS NOT NULL
AND y.id <= x.id
GROUP
BY x.id;
+----+-------+--------------+
| id | value | MAX(y.value) |
+----+-------+--------------+
| 1 | A | A |
| 2 | NULL | A |
| 3 | NULL | A |
| 4 | B | B |
| 5 | NULL | B |
+----+-------+--------------+
IF OBJECT_ID(N'tempdb..#Increment')>0
BEGIN
DROP TABLE #Increment
END
CREATE TABLE #Increment (
id INT
, Increment VARCHAR(10)
)
INSERT INTO #Increment (id, Increment)
SELECT 1, 'A' UNION
SELECT 2, NULL UNION
SELECT 3, NULL UNION
SELECT 4, 'B' UNION
SELECT 5, NULL UNION
SELECT 6, NULL UNION
SELECT 7, 'C' UNION
SELECT 8, NULL UNION
SELECT 9, NULL
;WITH cte
AS (SELECT T1.id,
Increment = COALESCE(T1.Increment, (SELECT TOP 1 T2.Increment
FROM #Increment T2
WHERE T2.id < T1.id
AND T2.Increment IS NOT NULL
ORDER BY id DESC))
FROM #Increment T1)
UPDATE T
SET T.Increment = C.Increment
FROM #Increment T
INNER JOIN cte C
ON T.id = C.id
WHERE T.Increment IS NULL
select * from #Increment

Merge two tables, inheriting values from one to another

I have two tables that I would like to display as a single result, using UNION or other technique.
The ID field relates both tables.
The second table has one field missing, so that missing value should be assumed from the first table.
The sample code below works, but is very slow for large datasets.
Is there any solution more efficient?
T1: T2:
+----+-------+--------+ +----+------+
| id | name | town | | id | name |
+----+-------+--------+ +----+------+
| 1 | Alice | London | | 1 | Bob |
| 2 | Alan | Zurich | +----+------+
+----+-------+--------+
Desired result:
+----+-------+--------+
| id | name | town |
+----+-------+--------+
| 1 | Alice | London |
| 2 | Alan | Zurich |
| 1 | Bob | London |
+----+-------+--------+
Sample code:
with T1 as
(
select * from
(
values
(1,'Alice','London') ,
(2,'Alan','Zurich')
) as t (id,name,town)
), T2 as
(
select * from
(
values
(1,'Bob')
) as t (id,name)
), T2WithTown as
(
select t2.id,t2.name,t1.town from T2
inner join T1 on t2.id=t1.id
)
select id,name,town from T1
union
select id,name,town from T2WithTown
The sample data shows both tables have distinct values. So I will prefer UNION ALL
Select ID, Name, Town From T1
UNION ALL
select T2.ID, T2.Name, T1.Town
from T1
INNER JOIN T2 on T2.id = T1.id
Just like this:
with T1 as
(
select * from
(
values
(1,'Alice','London') ,
(2,'Alan','Zurich')
) as t (id,name,town)
), T2 as
(
select * from
(
values
(1,'Bob')
) as t (id,name)
), T2WithTown as
(
select t2.id,t2.name,t1.town from T2
inner join T1 on t2.id=t1.id
)
select id,name,town from T1
union
select T2.id, T2.name, T1.town
from T1
inner join T2 on T2.id = T1.id
select id,name, town from t1
union
select id,name, (select top 1 town from t1 where t1.id=t2.id) from t2