How to insert data with subquery using SELECT * as VALUE? - mysql

I have 2 queries.
First query is
SELECT date
FROM tableA
WHERE
db='mydb' AND
date > (SELECT MAX(date) FROM tableB WHERE db='mydb')
LIMIT 1;
Second query is
INSERT INTO tableB (date, db, comment)
SELECT * FROM tableA
WHERE
db = 'mydb' AND
date = (date that i got from first query);
Data types are:
db(VARCHAR), date(date), comment(mediumblob).
statement SELECT * FROM tableA WHERE db = 'mydb' AND date = (date that i got from first query); returns exactly 1 row, but somehow second query returns that 1242 - Subquery returns more than 1 row.
I have tried to change SELECT * statement to each columns, but it didn't work on column comment. And it is impossible to do this on trigger because tableA is in system table.

As far as I understand the goal, you are trying to copy all fresh values from A to B. Here "fresh" means "date not exists in the target table yet".
I think it can be simplified to this query:
INSERT INTO `tableB` (`date`, `db`, `comment`)
SELECT `date`, `db`, `comment`
FROM `tableA`
WHERE `db` = 'mydb'
AND `date` > (SELECT MAX(`date`) FROM `tableB` WHERE `db` = 'mydb')

Related

Conditional insert query (Row count validation). (MYSQL)

I am trying to write a query that will count and compare the number of rows of two tables on two different databases. If they are equal then a record will be inserted into another table as 'Pass', else it will result in a 'Fail'.
I haven't been able to find any answers through google searches... Here is my query that isn't working:
select
case when
((select count(1) from db1.transaction) = (select count(1) from db2.transaction))
then
insert into db3.validation (test_result) values ('pass')
else
insert into db3.validation (test_result) values ('fail')
end;
You can do this by reversing the order. Do a single insert with a select choosing the value:
insert into db3.validation(test_result)
select (case when t1.cnt1 = t2.cnt2 then 'pass' else 'fail' end)
from (select count(1) as cnt1 from db1.transaction) t1 cross join
(select count(1) as cnt2 from db2.transaction) t2;
Note that I moved the subqueries from the case to a from clause, simply because I find them easier to read this way. You can keep them in the case if you prefer.

insert in mysql if select statement is true

I have a MySQL query :
select count(id) as tot from user where sponsor_id=10006 and exp > now();
The above query returns 1 as tot.
If the above query returns more than 1, it should insert a record in a table.
You can write something like:
insert into log
select 'there are more than one IDs'
from dual -- this is just a dummy table in mysql
where 1 <> (select count(id) as tot
from user
where sponsor_id=10006
and exp > now()
)
You can check this demo on SQLFiddle (without the exp>now() part).

Insert query based on number of rows

I want a query to insert a row into a table I know it is simple but the scenario is the table should not have more than 5 rows. If table has more than five rows I need to remove the old row(Or replace with new row ) (Based on the insert time stamp) then i need to insert a new row.If number of rows less than count 5 then i can directly insert a row.
Please share me the query.
How about something like this.
declare #count int
SELECT #count=COUNT(*)
from EP_ANSWERS
IF (#count<5)
// DO your insert here
ELSE
DELETE FROM TABLE
WHERE inserttimestamp = (SELECT x.inserttimestamp
FROM (SELECT MAX(t.inserttimestamp) AS inserttimestamp
FROM TABLE t) x)
// DO your insert here
If it is impossible for the table to have more than 5 rows:
DELETE FROM yourtable
WHERE 5 <= (SELECT COUNT(*) FROM yourtable)
AND yourtimestamp = (SELECT MIN(yourtimestamp) FROM yourtable)
;
INSERT INTO yourtable ...
;
If it is possible for the table to have more than 5 rows:
DELETE FROM yourtable
WHERE 5 <= (SELECT COUNT(*) FROM yourtable)
AND yourtimestamp NOT IN (SELECT yourtimestamp
FROM yourtable
ORDER BY yourtimestamp DESC
LIMIT 4)
;
INSERT INTO yourtable ...
;
It sounds like you want to put a trigger on the table to maintain this rule, in MySQL the something like this should work
CREATE TRIGGER trg__my_table__limit_rows
BEFORE INSERT
ON my_table
FOR EACH ROW
BEGIN
IF ((SELECT COUNT(1) FROM my_table) = 5)
BEGIN
DELETE FROM my_table
WHERE id = (SELECT MIN(id) FROM my_table) -- change this to fit your logic for which record should be removed
END
END
Some of the code here is in pseudo (you didn't wrote your schema), but i wrote where you need to complete your own code.
DECLARE #NumberOfRowsToInsert INT = -- select from the data you want to insert
DECLARE #MaxNumberOfRows INT = 5
DECLARE #NumberOfExistingRows INT
DECLARE #Query VARCHAR(MAX) = 'SELECT TOP #rows id FROM SomeTable ORDER BY createdDate ASC'
SELECT #NumberOfExistingRows = COUNT(*)
FROM SomeTable
SET #Query = REPLACE(#Query,'#rows',
CAST(#NumberOfRowsToInsert - (#MaxNumberOfRows - #NumberOfExistingRows))) AS VARCHAR(1))
CREATE TABLE #IdsToDelete(id INT PRIMARY KEY)
INSERT INTO #IdsToDelete
EXEC(#Query)
DELETE FROM SomeTable
WHERE id IN (SELECT * FROM #IdsToDelete)
-- insert here..

MYSQL Query : How to get values per category?

I have huge table with millions of records that store stock values by timestamp. Structure is as below:
Stock, timestamp, value
goog,1112345,200.4
goog,112346,220.4
Apple,112343,505
Apple,112346,550
I would like to query this table by timestamp. If the timestamp matches,all corresponding stock records should be returned, if there is no record for a stock for that timestamp, the immediate previous one should be returned. In the above ex, if I query by timestamp=1112345 then the query should return 2 records:
goog,1112345,200.4
Apple,112343,505 (immediate previous record)
I have tried several different ways to write this query but no success & Im sure I'm missing something. Can someone help please.
SELECT `Stock`, `timestamp`, `value`
FROM `myTable`
WHERE `timestamp` = 1112345
UNION ALL
SELECT `Stock`, `timestamp`, `value`
FROM `myTable`
WHERE `timestamp` < 1112345
ORDER BY `timestamp` DESC
LIMIT 1
select Stock, timestamp, value from thisTbl where timestamp = ? and fill in timestamp to whatever it should be? Your demo query is available on this fiddle
I don't think there is an easy way to do this query. Here is one approach:
select tprev.*
from (select t.stock,
(select timestamp from t.stock = s.stock and timestamp <= <whatever> order by timestamp limit 1
) as prevtimestamp
from (select distinct stock
from t
) s
) s join
t tprev
on s.prevtimestamp = tprev.prevtimestamp and s.stock = t.stock
This is getting the previous or equal timestamp for the record and then joining it back in. If you have indexes on (stock, timestamp) then this may be rather fast.
Another phrasing of it uses group by:
select tprev.*
from (select t.stock,
max(timestamp) as prevtimestamp
from t
where timestamp <= YOURTIMESTAMP
group by t.stock
) s join
t tprev
on s.prevtimestamp = tprev.prevtimestamp and s.stock = t.stock

How to insert conditionally

I create a temporary table #tbl(account, last_update). I have following two inserts from different source (could be tables from different databases) to insert account with last update date. For example
create table #tbl ([account] numeric(18, 0), [last_update] datetime)
insert into #tbl(account , last_update)
select table1.account, max(table1.last_update)
from table1 join…
group by table1.account
insert into #tbl(account , last_update)
select table2.account, max(table2.last_update)
from table2 join…
group by table2.account
The problem is this could cause duplicate account in the table #tbl. I either have to avoid it during each insert or remove the duplicate after both insert. Also, if there is account with two different last_update, I want the #tbl have the latest last_update. How do I achieve this conditional insert? Which one will have better performance?
Do you think you could rewrite your query to something like:
create table #tbl ([account] numeric(18, 0), [last_update] datetime)
insert into #tbl(account , last_update)
select theaccount, MAX(theupdate) from
(
select table1.account AS theaccount, table1.last_update AS theupdate
from table1 join…
UNION ALL
select table2.account AS theaccount, table2.last_update AS theupdate
from table2 join…
) AS tmp GROUP BY theaccount
The UNION ALL will build you 1 unique table combining table1 + table2 records. From there, you can act as if was a regular table, which means that you are able to find the max last_update for each record using a "group by"
insert into #tbl(account , last_update)
select account, last_update
from
(
select a.* from #table1 a where
last_update in( select top 1 last_update from #table1 b
where
a.account = b.account
order by last_update desc)
UNION
select a.* from #table2 a where
last_update in( select top 1 last_update from #table2 b
where
a.account = b.account
order by last_update desc)
) AS tmp