Mysql support this kind of "with" sql? - mysql

In postgres, I use this kind of sql often.
with list (id, name) as (
values
(1004007, 'aaa'),
(1002147, 'bbb'),
(1004493, 'ccc'),
(1007978, 'ddd'),
(1005218, 'eee'),
(1005507, 'fff')
)
select * from list;
Dose Mysql support that kind of sql ?

You can use select:
with list (id, name) as (
select 1004007, 'aaa' union all
select 1002147, 'bbb' union all
select 1004493, 'ccc' union all
select 1007978, 'ddd' union all
select 1005218, 'eee' union all
select 1005507, 'fff'
)
select l.*
from list l;
Here is a db<>fiddle. Note: This also works in Postgres.
Pre 8.0 versions of MySQL do not support with. You can create a derived table:
select list.*
from (select 1004007, 'aaa' union all
select 1002147, 'bbb' union all
select 1004493, 'ccc' union all
select 1007978, 'ddd' union all
select 1005218, 'eee' union all
select 1005507, 'fff'
) list;
This can then be used just a like a table reference.

Later 8.0 in mysql , we can use it like bellow
with
list (a, b, c) as (VALUES
ROW('1',-2,3),
ROW('5',7,9),
ROW('4',6,8)
)
select * from list;

Related

Check which IDs from a set do not exists in a table

I have a list of user IDs, like this:
757392,733602,749955,744304,746852,753904,755117,636163,564931,740787,751450,743799,643918,
749903,571888,30207,705953,749120,749001,749192,749978,750840,544228,702121,746246,383667,
558790,585628,592771,745818,749375,241209,749235,746860,748318,748016,748951,747321,748684,
748225,565375,748673,747869,748522,748335,744775,672229,578056,713127,740234,632608,711135,
746528,362131,742223,746567,745224,332989,439837,745418,673582,269584,742606,745135,746950,
476134,740830,742949,276934
I have a MySQL table users with the id field.
How do I check - using a query - which IDs of the ones I have do not exists in the users table?
This sounds like a simple problem to me, yet I couldn't find any example on StackOverflow which would address a fixed set of ID values.
I didn't know the find_in_set() function and took a more handcrafted approach. Not that it makes any sense given the first answer, but I'll post it anyway:
SELECT id
FROM (
SELECT '757392' AS id UNION
SELECT '733602' UNION
SELECT '749955' UNION
SELECT '744304' UNION
SELECT '746852' UNION
SELECT '753904' UNION
SELECT '755117' UNION
SELECT '636163' UNION
SELECT '564931' UNION
SELECT '740787' UNION
SELECT '751450' UNION
SELECT '743799' UNION
SELECT '643918' UNION
SELECT '749903' UNION
SELECT '571888' UNION
SELECT '30207' UNION
SELECT '705953' UNION
SELECT '749120' UNION
SELECT '749001' UNION
SELECT '749192' UNION
SELECT '749978' UNION
SELECT '750840' UNION
SELECT '544228' UNION
SELECT '702121' UNION
SELECT '746246' UNION
SELECT '383667' UNION
SELECT '558790' UNION
SELECT '585628' UNION
SELECT '592771' UNION
SELECT '745818' UNION
SELECT '749375' UNION
SELECT '241209' UNION
SELECT '749235' UNION
SELECT '746860' UNION
SELECT '748318' UNION
SELECT '748016' UNION
SELECT '748951' UNION
SELECT '747321' UNION
SELECT '748684' UNION
SELECT '748225' UNION
SELECT '565375' UNION
SELECT '748673' UNION
SELECT '747869' UNION
SELECT '748522' UNION
SELECT '748335' UNION
SELECT '744775' UNION
SELECT '672229' UNION
SELECT '578056' UNION
SELECT '713127' UNION
SELECT '740234' UNION
SELECT '632608' UNION
SELECT '711135' UNION
SELECT '746528' UNION
SELECT '362131' UNION
SELECT '742223' UNION
SELECT '746567' UNION
SELECT '745224' UNION
SELECT '332989' UNION
SELECT '439837' UNION
SELECT '745418' UNION
SELECT '673582' UNION
SELECT '269584' UNION
SELECT '742606' UNION
SELECT '745135' UNION
SELECT '746950' UNION
SELECT '476134' UNION
SELECT '740830' UNION
SELECT '742949' UNION
SELECT '276934') AS id_list
WHERE id NOT IN (
SELECT id
FROM users);
This is an option:
SELECT ids.id
FROM ( SELECT #i
, substring(#string, #start, #end-#start) id
FROM <BigTable>
, ( SELECT #string := <YourStringOfIds>
, #start:=0
, #end:=0
, #i:=0
, #len:=length(#string)
, #n:=#len-length(replace(#string,',',''))+1
) t
WHERE (#i := #i+1) <= #n
AND (#start := #end+1)
AND (#loc := locate(',',#string,#start))
AND #end := if(#loc!=0,#loc,#len+1)
) ids
LEFT JOIN <BigTable> u
ON u.id = ids.id
WHERE u.id is null
BigTable can be any table whose number of rows >= number of ids in your string.
Create temporary table, then fill it
CREATE TABLE tmp (
`id` INT NOT NULL,
PRIMARY KEY (`id`));
INSERT INTO tmp (id) VALUES (1),(2),(3),(4),(5),(6)
then make a query
SELECT tmp.id
FROM tmp
LEFT JOIN users u ON u.id = tmp.id
WHERE tmp.id IS NULL
finally drop the table
DROP TABLE tmp
You're looking for the IN clause with a negation. I.e. you can specify your list as the argument to the IN clause like so:
SELECT * FROM users
WHERE id NOT IN ( 757392,733602,749955,744304,746852,753904,755117,636163,564931,740787,751450,743799,643918,749903,571888,30207,705953,749120,749001,749192,749978,750840,544228,702121,746246,383667,558790,585628,592771,745818,749375,241209,749235,746860,748318,748016,748951,747321,748684,748225,565375,748673,747869,748522,748335,744775,672229,578056,713127,740234,632608,711135,746528,362131,742223,746567,745224,332989,439837,745418,673582,269584,742606,745135,746950,476134,740830,742949,276934 );
UPDATE
My bad - I didn't read the question properly.
So the correct way would be to go with UNIONs then outer join and filter by NULL, like this:
SELECT WantedIds.id
FROM users
RIGHT JOIN (
SELECT x.id
FROM (
SELECT '757392' AS id UNION
SELECT '733602' UNION
SELECT '749955' UNION
SELECT '744304' UNION
SELECT '746852' UNION
SELECT '753904' UNION
SELECT '755117' UNION
SELECT '636163' UNION
SELECT '564931' UNION
.
.
.
) x
) WantedIds
ON WantedIds.id = users.id
WHERE users.id IS NULL
You can use MySQL's find_in_set() function to check if a value exists in a commase separated list of values:
select * from your_table
where find_in_set(field_name,'757392,733602,749955,744304,746852,753904,755117,636163,564931,740787,751450')=0

Is possible to simplify multiple UNION ALL in mysql?

I have a MySQL query that always needs to compare 4 values, I need to add that values with rows using UNION ALL, but this code looks very large and I want to simplify it.
The code is the following:
SELECT
trimestre,
IF ((meta = 0) OR (meta is null) or not(meta REGEXP '[0-9]+'), :meta, meta) as valor
FROM
(
SELECT
trimestre,
valor AS meta
FROM
view_valores_indicadores
WHERE
anio = :anio
AND codigo_indicador = :codigo_indicador
AND alias_campo = 'meta'
UNION ALL
SELECT
1,
:meta
UNION ALL
SELECT
2,
:meta
UNION ALL
SELECT
3,
:meta
UNION ALL
SELECT
4,
:meta
ORDER BY
trimestre ASC
) AS T
GROUP BY
TRIMESTRE
I want to know if is possible to simplify that multiple UNION ALL's like
UNION ALL SELECT (row1, row1, row3...)

SUM string with comma (SQL Server Reporting Services)

I would like to get string sum check "column 1".
Do you have idea how to do it?
jack, john, bill, joe, sindy
Something similar to
=JOIN(Fields!Column1.Value, ",")
SAMPLE TABLE
CREATE TABLE #TEMP(COLUMN1 VARCHAR(100),COLUMN2 VARCHAR(100))
INSERT INTO #TEMP
SELECT 'jack',1
UNION ALL
SELECT 'john',1
UNION ALL
SELECT 'bill',1
UNION ALL
SELECT 'joe',1
UNION ALL
SELECT 'sindy',1
QUERY
If you need the value with comma separate values and count, you can avoid query before UNION ALL and execute the query only after UNION ALL.
SELECT NULL,COLUMN1,COLUMN2
FROM #TEMP
UNION ALL
SELECT DISTINCT 'TOTAL',
-- Here we convert to comma separated values
SUBSTRING(
(SELECT ', ' + COLUMN1
FROM #TEMP T2
--WHERE C2.Id=Id AND C2.COLUM=COLUM
FOR XML PATH('')),2,200000) COLUMN1,
COUNT(COLUMN1) COLUMN2
FROM #TEMP T1

How to join 2 tables and order them?

I have 2 tables: _divions and _employee. In _employee there's a column division which is id_division in the table _division. I need to order them by the _division order first.
This table has a column order. I have tried this SQL statement, but it doesn't do much:
SELECT
e . *
FROM
`_employee` AS `e`
JOIN
`_division` AS d
ORDER BY
d.order,
e.division,
e.order
You missing ON clause. Try this
SELECT e.*
FROM _employee AS e
JOIN _division AS d ON d.id_division = e.division
// ^^^^ Missing
ORDER BY e.order
Below query may help. (Assuming there are divisions with no employees)
with employee as
(
select 'NISHA' ENAME, '10' EDIV FROM DUAL
UNION
SELECT 'ABC' ENAME, '10' EDIV FROM DUAL
UNION
SELECT 'DEF' ENAME, '15' EDIV FROM DUAL
UNION
SELECT 'GHI' ENAME, '20' EDIV FROM DUAL
),
DIVISION AS
(
SELECT '10' DIV_ID, 'INFO-TECH' DIV_DESC FROM DUAL
UNION
SELECT '15' DIV_ID, 'HUMAN RESOURCES' DIV_DESC FROM DUAL
UNION
SELECT '20' DIV_ID, 'SALES' DIV_DESC FROM DUAL
UNION
SELECT '25' DIV_ID, 'RESEARCH' DIV_DESC FROM DUAL
)
SELECT *
FROM EMPLOYEE, DIVISION WHERE
employee.EDIV (+) = DIVISION.DIV_ID
ORDER BY DIV_DESC, ENAME
If all employees would definitely have a division,then use employee.EDIV = DIVISION.DIV_ID instead of employee.EDIV (+) = DIVISION.DIV_ID

MySQL; Get information from 3 table same time

People
here is my little problem.
I have three table:
a_names_1
b_names_2
c_names_3
they are same by structure. all of them has two item: name and used
Is there any QUERY to run to get and count all the 'name' that has 'used'=1 from all those three tables together.
I've tried this one, but didn't work:
(SELECT COUNT(*) 'name' from a_names_1) UNION
(SELECT COUNT(*) 'name' from a_names_2) UNION
(SELECT COUNT(*) 'name' from a_names_3) WHERE `used`=1
I'm using PHPMyAdmin for MySQL.
Any Help would be appreciated.. thanks in advance
This query outputs count of distinct names from all tables with used=1
select count(distinct name)
from
(
select name,used from a_names_1 where used=1
union all
select name,used from a_names_2 where used=1
union all
select name,used from a_names_3 where used=1
) t
If you need to SUM all USED for each NAME from all tables and output only with SUM of used=1 then:
select count(*) from
(
select name, SUM(used)
from
(
select name,used from a_names_1
union all
select name,used from a_names_2
union all
select name,used from a_names_3
) t
GROUP BY name
HAVING SUM(used)=1
) t1
select count(*) as name
from
(
select name, used from a_names_1
union
select name, used from a_names_2
union
select name, used from a_names_3) t
where t.used = 1
Probably this is slow, because you lose the index optimizations. What I would do is do the three queries, something like
SELECT SUM('name') AS name_sum
FROM ((SELECT COUNT(*) 'name' from a_names_1 WHERE `used`=1)
UNION (SELECT COUNT(*) 'name' from a_names_2 WHERE `used`=1));
If this doesn't work, it is probably a problem with the usage of name
Maybe you wanted this way:
select count(*) as cnt
from
(
select name from a_names_1 t1 where t1.used = 1
union
select name from a_names_2 t2 where t2.used = 1
union
select name from a_names_3 t3 where t3.used = 1
) t
The straight forward solution;
SELECT SUM(used) FROM (
SELECT used FROM a_names_1 WHERE used=1
UNION ALL
SELECT used FROM a_names_2 WHERE used=1
UNION ALL
SELECT used FROM a_names_3 WHERE used=1
) a
SQLfiddle for testing
An alternative if you have an index on used (and the only values of used are 0 or 1) is to just do the counting using the index;
SELECT SUM(used) total FROM (
SELECT SUM(used) used FROM a_names_1
UNION ALL
SELECT SUM(used) FROM a_names_2
UNION ALL
SELECT SUM(used) FROM a_names_3
) a
SQLfiddle for this example.
If you look at the query plan of the latter query, you can see it uses the indexes effectively.