MYSQL Query: combine columns and get count - mysql

I have about 9 tables that contain the same type of field. I would like to combine the 9 of them FIRST, and then get the distinct count of unique values in that combined column. This is what I've tried so far, but to no avail. I'm not also not sure this is the most efficient way to return this value?
SELECT COUNT(DISTINCT aircraft_id) FROM
(
SELECT aircraft_id FROM database.a_message UNION ALL
SELECT aircraft_id FROM database.b_message UNION ALL
SELECT aircraft_id FROM database.c_message UNION ALL
SELECT aircraft_id FROM database.d_message UNION ALL
SELECT aircraft_id FROM database.e_message UNION ALL
SELECT aircraft_id FROM database.f_message UNION ALL
SELECT aircraft_id FROM database.g_message UNION ALL
SELECT aircraft_id FROM database.h_message UNION ALL
SELECT aircraft_id FROM database.i_message
) ;

SELECT DISTINCT aircraft_id,count(aircraft_id) FROM
(
SELECT aircraft_id FROM database.a_message UNION ALL
SELECT aircraft_id FROM database.b_message UNION ALL
SELECT aircraft_id FROM database.c_message UNION ALL
SELECT aircraft_id FROM database.d_message UNION ALL
SELECT aircraft_id FROM database.e_message UNION ALL
SELECT aircraft_id FROM database.f_message UNION ALL
SELECT aircraft_id FROM database.g_message UNION ALL
SELECT aircraft_id FROM database.h_message UNION ALL
SELECT aircraft_id FROM database.i_message
) group by aircraft_id;
or
select aircraft_id,count(aircraft_id)
(
SELECT DISTINCT aircraft_id FROM
(
SELECT aircraft_id FROM database.a_message UNION ALL
SELECT aircraft_id FROM database.b_message UNION ALL
SELECT aircraft_id FROM database.c_message UNION ALL
SELECT aircraft_id FROM database.d_message UNION ALL
SELECT aircraft_id FROM database.e_message UNION ALL
SELECT aircraft_id FROM database.f_message UNION ALL
SELECT aircraft_id FROM database.g_message UNION ALL
SELECT aircraft_id FROM database.h_message UNION ALL
SELECT aircraft_id FROM database.i_message
)
) group by aircraft_id;

Related

Insert unique random number with recursive MySQL

I want to populate a table with unique random numbers without using a procedure.
I've tried using this reply to do it but not success.
What I'm trying to do is something like this but validating that numbers are not repeated:
INSERT into table (row1,row2)
WITH RECURSIVE
cte AS ( SELECT 0 num, LPAD(FLOOR(RAND() * 99999999),8,0) random_num
UNION ALL
SELECT num+1, LPAD(FLOOR(RAND() * 99999999),8,0) random_num
FROM cte WHERE num < 100000-1)
SELECT random_num, null
FROM cte;
In the example above, I am able to generate random values and insert them but without validating that the numbers are not repeated.
I have tried to do this:
INSERT into table (row1,row2)
WITH RECURSIVE
cte AS ( SELECT 0 num, LPAD(FLOOR(RAND() * 99999999),8,0) random_num
UNION ALL
SELECT num+1, LPAD(FLOOR(RAND() * 99999999),8,0) random_num
FROM cte WHERE num < 100000-1 AND random_num NOT IN (SELECT random_num FROM cte WHERE random_num IS NOT NULL))
SELECT random_num, null
FROM cte;
but the condition AND random_num NOT IN (SELECT random_num FROM cte WHERE random_num IS NOT NULL) in the where case, causes an SQL Error [4008] [HY000]: Restrictions imposed on recursive definitions are violated for table 'cte'
Any suggestions of how to do it? thank you!.
This could be an option. Generate all possible values, sort randomly and take desired number of entries.
CREATE TABLE random_data (
row1 INT PRIMARY KEY AUTO_INCREMENT,
row2 VARCHAR(10) NOT NULL,
UNIQUE KEY _Idx1 ( row2 )
);
INSERT INTO random_data (row2)
SELECT LPAD(num, 8, 0)
FROM (
SELECT h * 10000000 + g * 1000000 + f * 100000 + e * 10000 + d * 1000 + c * 100 + b * 10 + a AS num
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) ta
JOIN (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) tb
JOIN (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) tc
JOIN (SELECT 0 d 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) td
JOIN (SELECT 0 e 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) te
JOIN (SELECT 0 f 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) tf
JOIN (SELECT 0 g 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) tg
JOIN (SELECT 0 h 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) th
) n
ORDER BY RAND()
LIMIT 100000;
If you have a table - any table - with e.g. 100 rows then you can generate million distinct random numbers between 0 and 99999999 as follows:
select distinct floor(rand() * 100000000)
from t as t0, t as t1, t as t2
limit 1000000
Note that because of distinct you will need to generate a bigger number of rows so that you get desired number of rows after distinct.

Get number of monday in a rangedate mysql

Get number of monday in a rangedate MySQL, I run this code but it give me result 0:
select count(*) from tarif where weekday(`end_tarif`<= '2019-02-21'AND `start_tarif`>='2019-02-05') = 0;
my table:
CREATE TABLE `tarif` (
`tarif_id` int(11) NOT NULL AUTO_INCREMENT,
`start_tarif` date NOT NULL,
`end_tarif` date NOT NULL,
`day_tarif` varchar(50) NOT NULL,
PRIMARY KEY (`tarif_id`)
);
INSERT INTO `tarif` VALUES (1, '2019-02-01', '2019-02-10', '10'),
(2, '2019-02-11', '2019-02-20', '20'),
(3, '2019-02-21', '2019-02-28', '10'),
(4, '2019-03-01', '2019-02-10', '15');
You can use a solution using a calendar table. So you can use a solution like the following:
1. create a table with calendar data
-- create the table "calendar"
CREATE TABLE `calendar` (
`dateValue` DATE
);
-- insert the days to the table "calendar"
INSERT INTO calendar
SELECT adddate('1970-01-01',t4*10000 + t3*1000 + t2*100 + t1*10 + t0) gen_date from
(select 0 t0 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) t0,
(select 0 t1 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) t1,
(select 0 t2 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) t2,
(select 0 t3 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) t3,
(select 0 t4 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) t4
HAVING gen_date BETWEEN '2019-01-01' AND '2019-12-31'
You can find the script to generate the calendar data on StackOverflow:
How to populate a table with a range of dates?
2. create the table with your data (with monday tarif)
-- create the table "tarif"
CREATE TABLE tarif (
tarif_id INT(11) NOT NULL AUTO_INCREMENT,
start_tarif DATE NOT NULL,
end_tarif DATE NOT NULL,
day_tarif VARCHAR(50) NOT NULL,
monday_tarif VARCHAR(50) NOT NULL,
PRIMARY KEY (tarif_id)
);
-- insert the tarif information
INSERT INTO tarif VALUES
(1, '2019-02-01', '2019-02-10', '10', '5'),
(2, '2019-02-11', '2019-02-20', '20', '5'),
(3, '2019-02-21', '2019-02-28', '10', '5'),
(4, '2019-03-01', '2019-02-10', '15', '5');
Note: To create a useful example I added the column monday_tarif and insert the value 5 on every date range.
3. get the result
Now you can get all days of your needed range (between 2019-02-05 and 2019-02-21) from the calendar table. With a LEFT JOIN you add your tarif table to all days of date range.
With a CASE WHEN and the condition DAYOFWEEK = 2 or DAYNAME = 'Monday' you can check if the current date is a Monday or not, to get the correct tarif value of the day.
SELECT SUM(CASE WHEN DAYOFWEEK(cal.dateValue) = 2 THEN tarif.monday_tarif ELSE tarif.day_tarif END) AS sumWithMondayTarif
FROM calendar cal
LEFT JOIN tarif ON cal.dateValue BETWEEN start_tarif AND end_tarif
WHERE cal.dateValue BETWEEN '2019-02-05' AND '2019-02-21';
You can also use a SELECT with a sub select of the calendar:
SELECT SUM(CASE WHEN DAYOFWEEK(cal.dateValue) = 2 THEN tarif.monday_tarif ELSE tarif.day_tarif END) AS sumWithMondayTarif FROM (
SELECT adddate('1970-01-01',t4*10000 + t3*1000 + t2*100 + t1*10 + t0) dateValue FROM
(select 0 t0 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) t0,
(select 0 t1 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) t1,
(select 0 t2 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) t2,
(select 0 t3 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) t3,
(select 0 t4 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) t4
HAVING dateValue BETWEEN '2019-02-05' AND '2019-02-21'
) cal LEFT JOIN tarif ON cal.dateValue BETWEEN start_tarif AND end_tarif
demo on dbfiddle.uk
Below mentioned query is for sundays count. you can modify it as per your requirement
select ROUND((
(unix_timestamp(`end_tarif`) - unix_timestamp(`start_tarif`) )/(24*60*60)
-7+WEEKDAY(`start_tarif`)-WEEKDAY(`end_tarif`)
)/7)
+ if(WEEKDAY(`start_tarif`) <= 6, 1, 0)
+ if(WEEKDAY(`end_tarif`) >= 6, 1, 0) as Sunday
from tarif
where `end_tarif`<= '2019-02-21' AND `start_tarif`>='2019-02-05' ;

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

Insert where in join, code confused

This code returns me the most used words in a column in TEXT format called description and is on the table 'messages`.
However I can not stick this in the WHERE code:
messages.tag = 'HELLO'
I need it to do what it already does, but with this WHERE I tried this code and gave not sure:
SELECT message, count(message) as count
FROM (
SELECT
messages.id,
SUBSTRING_INDEX(SUBSTRING_INDEX(messages.message, ' ', count.n), ' ', -1) as message
FROM
(select (h*100+t*10+u+1) n from
(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) A,
(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) B,
(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) C
) as count
INNER JOIN messages
ON CHAR_LENGTH(messages.message)-CHAR_LENGTH(REPLACE(messages.message, ' ',''))>=count.n-1
ORDER BY id, n
) x
WHERE LENGTH(message) >= 5
AND messages.tag = 'HELLO'
GROUP BY message
ORDER BY count DESC
LIMIT 10
You have to move that where clause into the subquery. The messages alias is not known in the outer query:
FROM (SELECT messages.id,
SUBSTRING_INDEX(SUBSTRING_INDEX(messages.message, ' ', count.n), ' ', -1) as message
FROM (select (h*100+t*10+u+1) n
from (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) A,
(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) B,
(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) C
) count INNER JOIN
messages
ON CHAR_LENGTH(messages.message)-CHAR_LENGTH(REPLACE(messages.message, ' ','')) >= count.n-1
WHERE messages.tag = 'HELLO'
ORDER BY id, n
) x
The other condition stays in the outer query.
Try this,
I think messages.tag should be like, not equal to 'HELLO'
SELECT message, count(message) as count
FROM (
SELECT
messages.id,
SUBSTRING_INDEX(SUBSTRING_INDEX(messages.message, ' ', count.n), ' ', -1) as message
FROM
(
select (h*100+t*10+u+1) n
from
(
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) A,
(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) B,
(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) C
) count
INNER JOIN messages
ON CHAR_LENGTH(messages.message)-CHAR_LENGTH(REPLACE(messages.message, ' ',''))>=count.n-1
WHERE messages.tag like '%HELLO%'
ORDER BY id, n
) x
WHERE LENGTH(message) >= 5
GROUP BY message
ORDER BY count DESC
LIMIT 10

Mysql Query to find distinct characters in a string

Is there a way to write recursive query in mysql. Equivalent of connect by (level or Prior) in oracle. I searched google as well as stackoverflow and there is no direct eqivalent. But is there any work around to get it.
I have a string, i have to iterate through individual characters in the string and print only the distinct characters of the string.
Input:
recursive
Output:
recusiv
I came up with this "simple" solution.
Functions used:
GROUP_CONCAT: http://dev.mysql.com/doc/refman/5.0/en/group-by-functions.html#function_group-concat
SUBSTRING http://dev.mysql.com/doc/refman/5.0/en/string-functions.html#function_substring
Live demo: http://www.sqlfiddle.com/#!2/d41d8/19186
SELECT
GROUP_CONCAT( chars.c SEPARATOR '') AS allchars
FROM (
SELECT DISTINCT
SUBSTRING( str.str, pos.pos, 1 ) AS c
FROM
( SELECT x1.x + x2.x*10 AS pos
FROM
( SELECT 0 AS x 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
) AS x1
INNER JOIN
( SELECT 0 AS x 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
) AS x2
) AS pos
INNER JOIN
( SELECT 'recursive' AS str UNION ALL
SELECT 'XYZ'
) AS str
) AS chars