I want to insert into a table using a select statement as well as a unique value. The following query returns an error that the column counts are not matching. What am I missing?
insert into moving_average (ma_symbol, ma_date, ma5)
values
(
select 'A', max(temp.histDate), avg(temp.histClose)
from
(
select hd.histDate, hd.histClose
from historical_data hd
where symbol like 'A' order by hd.histDate asc limit 5
) temp
);
Try this:
insert into moving_average (ma_symbol, ma_date, ma5)
select 'A', max(histDate), avg(histClose)
from (select (histDate), (histClose)
from historical_data
where symbol like 'A'
order by histDate asc
limit 5) temp;
INSERT INTO ... SELECT statement does not use VALUES keyword.
Related
I have a mysql table with only 3 columns (id - primary key / status / timestamp). Periodically I receive a status message which can be 0 or 1 and I need to insert it in that table but only if the last status inserted is different.
Is there any way to do this is only one mysql query ?
Basically I need to do this :
SELECT status FROM `status_e_distr_c01` order by id DESC LIMIT 1
Then compare my status message with select result and if is different then do insert, if not...do nothing...
So how can I do this in one mysql query ?
Thank you very much
Assuming that the values of the columns that you want to insert are :status, :timestamp you can do it like this:
INSERT INTO status_e_distr_c01 (status, timestamp)
SELECT :status, :timestamp
FROM dual
WHERE :status <>
COALESCE((SELECT status FROM status_e_distr_c01 ORDER BY id DESC LIMIT 1), NOT :status)
The code will work even if the table is empty.
You may omit FROM dual if your version of MySql is 5.7+.
See a simplified demo.
INSERT INTO status_e_distr_c01 (status)
SELECT #new_status
FROM ( SELECT status
FROM status_e_distr_c01
ORDER BY ts DESC LIMIT 1 ) subquery
WHERE subquery.status != #new_status;
PS. Will fail if destination table is empty. The most first row must be inserted without thes checking.
UPDATE
INSERT INTO status_e_distr_c01 (status)
SELECT #new_status
WHERE #new_status != COALESCE(( SELECT status
FROM status_e_distr_c01
ORDER BY ts DESC LIMIT 1 ), 2);
Works on empty table too.
fiddle
The same as stored procedure:
CREATE PROCEDURE insert_if_changed (IN new_status INT)
INSERT INTO status_e_distr_c01 (status)
SELECT new_status
WHERE new_status != COALESCE(( SELECT status
FROM status_e_distr_c01
ORDER BY ts DESC LIMIT 1 ), 2);
fiddle
You can use an INSERT ... SELECT ... FROM the dual pseudo table and check if the target table is empty or the new status differs from the last one selected in a subquery.
INSERT INTO status_e_distr_c01
(status)
SELECT ?
FROM dual
WHERE NOT EXISTS (SELECT *
FROM status_e_distr_c01)
OR ? <> (SELECT status
FROM status_e_distr_c01
ORDER BY id DESC
LIMIT 1);
The following code returns Operand should contain 1 columns.
SELECT
CASE WHEN
(SELECT COUNT(1) FROM `student` WHERE `join_date` > '2017-03-21 09:00:00') > 0
THEN
(SELECT * FROM `student` >= CAST(CAST('2017-03-21 09:00:00' AS DATE) AS DATETIME)
END
but the following works. Why?
SELECT
CASE WHEN
(SELECT COUNT(1) FROM `student` WHERE `join_date` > '2017-03-21 00:00:00') > 0
THEN
(SELECT `foo`)
ELSE
(SELECT `bar`)
END
How if i want to perform checking and execute 2 different queries according to the checking result.
I want to achieve following result (works fine in sql)
IF (SELECT COUNT(*) FROM table WHERE term LIKE "term") > 4000
EXECUTE (SELECT * FROM table1)
ELSE
EXECUTE (SELECT * FROM table2)
If you force your subselect tor return only a row the also the first select work
SELECT
CASE WHEN
(SELECT COUNT(1) FROM `student` WHERE `join_date` > '2017-03-21 00:00:00') > 0
THEN
(SELECT * FROM `student` order by your_column limit 1)
ELSE
(SELECT * FROM `teacher` order by your_column limit 1)
END
you should also add proper order by on the column your need (in the sample named your_column ) for obtain the valid first row
You can select from both tables using UNION ALL and excluding conditions.
SELECT * FROM `student`
WHERE EXISTS (SELECT * FROM `student` WHERE `join_date` > '2017-03-21 00:00:00')
UNION ALL
SELECT * FROM `teacher`
WHERE NOT EXISTS (SELECT * FROM `student` WHERE `join_date` > '2017-03-21 00:00:00')
Note that the table schemas should be the same.
Is it not possible to do an Operation like this in an SQL Statement?
INSERT INTO ships (user_id,construction_time, fleet_id, template_id, experience, hitpoints,unit_4,rof)
VALUES (11, UNIX_TIMESTAMP(), (-5002), (SELECT id, value_9, value_5, min_unit_4, rof FROM ship_templates WHERE ship_torso >2 ORDER BY RAND() LIMIT 1))
Copy one table data to another :-
INSERT INTO TARGET_TABLE (`col1`,`col2`) SELECT `col1`,`col2` FROM SOURCE_TABLE;
Try this:-
INSERT INTO ships (ser_id,construction_time, fleet_id, template_id, experience, hitpoints,unit_4,rof)
SELECT '11',UNIX_TIMESTAMP(),(-5002),id, value_9, value_5, min_unit_4, rof FROM ship_templates WHERE ship_torso >2 ORDER BY RAND() LIMIT 1;
I have one table and i want to check that for one column all value are same.
following is the entry in my table.
two column
rid,value
(1,1)
(1,1)
(2,1)
(2,0)
(2,0)
(3,0)
(3,0)
(3,0)
I want query which gives me rid 1 because all of its value is 1. all record for rid 1 has value 1 and rid 2 and 3 does not has all value as 1 so they should not be selected.
Using group by and having can get what you want:
SELECT rid, value
FROM my_table
GROUP BY rid
HAVING COUNT( distinct value) = 1
UPDATE
According to the comment, filter the value will get the result:
SELECT *
FROM
(
SELECT rid, value
FROM my_table
GROUP BY rid
HAVING COUNT( distinct value) = 1
) AS T1
WHERE value = 1
If the values would only be 1 or 0, then you could do this trick:
SELECT rid, value
FROM my_table
GROUP BY rid
HAVING COUNT( * ) = SUM(value)
You can do like this:
CREATE TABLE my_table (
id varchar(255),
col_value varchar(255)
);
INSERT INTO my_table
VALUES
('1','1'),
('1','1'),
('2','1'),
('2','1'),
('2','1'),
('2','4'),
('3','1'),
('3','1');
Query for selection:
SELECT src.* FROM
(
SELECT DISTINCT t1.* FROM my_table AS t1
) AS src
WHERE src.id NOT IN(
SELECT test.id
FROM
(
SELECT DISTINCT t1.* FROM my_table AS t1
) AS test
GROUP BY test.id
HAVING COUNT(*) > 1
)
fiddle here.
Let's say I was looking for the second most highest record.
Sample Table:
CREATE TABLE `my_table` (
`id` int(2) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
`value` int(10),
PRIMARY KEY (`id`)
);
INSERT INTO `my_table` (`id`, `name`, `value`) VALUES (NULL, 'foo', '200'), (NULL, 'bar', '100'), (NULL, 'baz', '0'), (NULL, 'quux', '300');
The second highest value is foo. How many ways can you get this result?
The obvious example is:
SELECT name FROM my_table ORDER BY value DESC LIMIT 1 OFFSET 1;
Can you think of other examples?
I was trying this one, but LIMIT & IN/ALL/ANY/SOME subquery is not supported.
SELECT name FROM my_table WHERE value IN (
SELECT MIN(value) FROM my_table ORDER BY value DESC LIMIT 1
) LIMIT 1;
Eduardo's solution in standard SQL
select *
from (
select id,
name,
value,
row_number() over (order by value) as rn
from my_table t
) t
where rn = 1 -- can pick any row using this
This works on any modern DBMS except MySQL. This solution is usually faster than solutions using sub-selects. It also can easily return the 2nd, 3rd, ... row (again this is achievable with Eduardo's solution as well).
It can also be adjusted to count by groups (adding a partition by) so the "greatest-n-per-group" problem can be solved with the same pattern.
Here is a SQLFiddle to play around with: http://sqlfiddle.com/#!12/286d0/1
This only works for exactly the second highest:
SELECT * FROM my_table two
WHERE EXISTS (
SELECT * FROM my_table one
WHERE one.value > two.value
AND NOT EXISTS (
SELECT * FROM my_table zero
WHERE zero.value > one.value
)
)
LIMIT 1
;
This one emulates a window function rank() for platforms that don't have them. It can also be adapted for ranks <> 2 by altering one constant:
SELECT one.*
-- , 1+COALESCE(agg.rnk,0) AS rnk
FROM my_table one
LEFT JOIN (
SELECT one.id , COUNT(*) AS rnk
FROM my_table one
JOIN my_table cnt ON cnt.value > one.value
GROUP BY one.id
) agg ON agg.id = one.id
WHERE agg.rnk=1 -- the aggregate starts counting at zero
;
Both solutions need functional self-joins (I don't know if mysql allows them, IIRC it only disallows them if the table is the target for updates or deletes)
The below one does not need window functions, but uses a recursive query to enumerate the rankings:
WITH RECURSIVE agg AS (
SELECT one.id
, one.value
, 1 AS rnk
FROM my_table one
WHERE NOT EXISTS (
SELECT * FROM my_table zero
WHERE zero.value > one.value
)
UNION ALL
SELECT two.id
, two.value
, agg.rnk+1 AS rnk
FROM my_table two
JOIN agg ON two.value < agg.value
WHERE NOT EXISTS (
SELECT * FROM my_table nx
WHERE nx.value > two.value
AND nx.value < agg.value
)
)
SELECT * FROM agg
WHERE rnk = 2
;
(the recursive query will not work in mysql, obviously)
You can use inline initialization like this:
select * from (
select id,
name,
value,
#curRank := #curRank + 1 AS rank
from my_table t, (SELECT #curRank := 0) r
order by value desc
) tb
where tb.rank = 2
SELECT name
FROM my_table
WHERE value < (SELECT max(value) FROM my_table)
ORDER BY value DESC
LIMIT 1
SELECT name
FROM my_table
WHERE value = (
SELECT min(r.value)
FROM (
SELECT name, value
FROM my_table
ORDER BY value DESC
LIMIT 2
) r
)
LIMIT 1