MySQL Update Subquery problem - mysql

I am stuck on an update query that is using a subquery and have not been able to figure it out after reading the manual and trying different ideas. Below is the table & query. Tables Temp_2, Temp_3 & Temp_4 both have 33 rows in them and no null values.
Any ideas on how to resolve this?
CREATE TABLE temp_2 (
date_value date default NULL,
close_adj_value_1 double default NULL);
CREATE TABLE temp_3 (
date_value date default NULL,
first_close_adj_value_1 double default NULL);
CREATE TABLE temp_4 (
date_value date default NULL,
pct_return_1 double default NULL);
INSERT INTO temp_4 (date_value) SELECT date_value FROM temp_2;
UPDATE temp_4
SET pct_return_1 =
(SELECT ((temp_2.close_adj_value_1 / temp_3.first_close_adj_value_1) - 1)
FROM temp_2,temp_3
WHERE temp_2.date_value = temp_3.date_value);
Thanks,
Eric

Since you're using MySQL, you can employ its multi-table UPDATE syntax:
UPDATE temp_4
JOIN temp_2 USING (date_value)
JOIN temp_3 USING (date_value)
SET temp_4.pct_return_1 = (temp_2.close_adj_value_1 /
temp_3.first_close_adj_value_1) - 1;
I assume you want to use the date_value column to correlate the rows in temp_4 to the rows in the other tables.
An alternative solution you could use is to insert all the values into an empty temp_4 table in one go:
INSERT INTO temp_4 (date_value, pct_return_1)
SELECT temp_2.date_value,
(temp_2.close_adj_value_1 / temp_3.first_close_adj_value_1) - 1
FROM temp_2 JOIN temp_3 USING (date_value);

The answer from Bill shown below solved my problem:
INSERT INTO temp_4 (date_value, pct_return_1)
SELECT temp_2.date_value,
(temp_2.close_adj_value_1 / temp_3.first_close_adj_value_1) - 1
FROM temp_2 JOIN temp_3 USING (date_value);

Related

Woes using UPDATE with a CTE in MySQL (MariaDB)

I'm going crazy trying to get UPDATE to work with a CTE in MySQL.
Here's a simplified schema of sa_general_journal:
CREATE TABLE `sa_general_journal` (
`ID` int(10) unsigned NOT NULL AUTO_INCREMENT,
`Transaction_ID` int(10) unsigned DEFAULT NULL COMMENT 'NULL if not split, same as ID for split records',
`Date` timestamp NOT NULL DEFAULT current_timestamp(),
…
`Statement_s` int(10) unsigned DEFAULT NULL,
…
`Name` varchar(255) DEFAULT NULL,
…
PRIMARY KEY (`ID`),
…
) ENGINE=InnoDB AUTO_INCREMENT=25929 DEFAULT CHARSET=utf8;
Some records are "split," for example, a credit card statement amount might have a sales tax amount that is split out. In such cases, both parts of the split record have the same ID in the Transaction_ID field.
When records are imported in bulk, they can't refer to last_insert_ID in order to fill in the Transaction_ID field, thus the need to go clean these up afterward.
This was my first, naive attempt, which said I had an error near UPDATE. Well duh.
WITH cte AS (
SELECT
ID,
MIN(ID) OVER(PARTITION BY `Date`, `Name`, Statement_s) AS Trans,
Transaction_ID
FROM sa_general_journal
WHERE Transaction_ID = 0)
UPDATE cte
SET Transaction_ID = Trans
The CTE itself seems to work, as I can follow it with SELECT * FROM cte and get what I expected.
So I started searching StackOverflow, and discovered that CTEs are not updatable, but that you need to join them to what you want to update. "No problem!" I think, as I code this up:
WITH cte AS (
SELECT
ID,
MIN(ID) OVER(PARTITION BY `Date`, `Name`, Statement_s) AS Trans,
Transaction_ID
FROM sa_general_journal
WHERE Transaction_ID = 0)
UPDATE sa_general_journal gj, cte
SET gj.Transaction_ID = cte.Trans
WHERE gj.ID = cte.ID
No joy. Same error message.
My understanding is that in MySQL, you don't need a column list, but I did also try this using the column list (a, b, c), with the proper columns referenced in the UPDATE statement, but it still said I had a problem near UPDATE.
There are incredibly few examples of using UPDATE with WITH on the Internet! I found one, from Percona, which I used to create my attempt above, and then found another very similar example from MySQL itself.
Thanks in advance for any help offered!
CTE is a part of subquery definition, not a part of the whole query. The query must be specified after CTE. CTE cannot be used itself. So
UPDATE sa_general_journal gj
JOIN (WITH cte AS ( SELECT
ID,
MIN(ID) OVER(PARTITION BY `Date`, `Name`, Statement_s) AS Trans,
Transaction_ID
FROM sa_general_journal
WHERE Transaction_ID = 0)
SELECT * FROM cte) subquery ON gj.ID = subquery.ID
SET gj.Transaction_ID = subquery.Trans
CTEs work with UPDATE in MySQL 8, but not MariaDB 10.x.

MySQL - Operand should contain 1 column(s) when insert row from other table

While working on a system I'm creating, I attempted to use the following query in my project:
INSERT INTO wpr9_posts ( `post_date`,`post_content`,`post_title`,`post_status`,`post_type` )
VALUES ((SELECT '2020-08-28 18:30:43' as post_date,`image`,`name`,'publish' as post_status,'post' as post_type FROM `play` WHERE `catid` = 863 ))
This query inserts a row from a table to another table.
Is there a simple fix to this, or another way to write my query?
You don't need the values keyword when using an insert-select statement:
INSERT INTO wpr9_posts ( `post_date`,`post_content`,`post_title`,`post_status`,`post_type` )
SELECT '2020-08-28 18:30:43' as post_date,`image`,`name`,'publish' as post_status,'post' as post_type FROM `play` WHERE `catid` = 863

MySQL - get date column from a table

I have a MySQL db with a MappingTable which consists of two columns. First column is a date column and another is ID - Autoincrement int column. I created this table for mapping dates and the ID's. When I query the date column with dates to retrieve the ID, no rows are getting selected. Any reason?
I tried
date_format in the SELECT query
str_to_date while checking in the WHERE clause
Compared like current_date > "2016-07-12" AND current_date <= "2016-07-12"
IfI compare LIKE "2016-07-1%" I'm getting matching rows but if I select "2016-07-12%" though there are matching rows, it is giving 0 rows.
I defined my column as DATE only.
Anything I'm missing here?
CREATE TABLE `mapping_table` (
`Current_date` date DEFAULT NULL,
`id` int(11) NOT NULL AUTO_INCREMENT, PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=26 DEFAULT CHARSET=utf8;
My question is, I want to select something like this.
select id from mapping_table where current_date="2016-07-12";
I tried with all approaches as mentioned above, but no rows are not retrieving.
use back tick on columns and table names so it wont be read/parse as keyword.
select `id` from `mapping_table` where `current_date` = "2016-07-12";
In the sample you provided you should use a date_format
select id from mapping_table where current_date= DATE_FORMAT("2016-07-12",'%Y-%d-%m') ;
or use a range
select id from mapping_table where current_date
BETWEEN DATE_FORMAT("2016-07-12",'%Y-%d-%m')
and DATE_FORMAT("2016-07-10",'%Y-%d-%m')

why is the sum of five 1 = 4

the base query works as intenden, but when i try to sum the first columns, its supose to be 5, but insted i get 4, why?
base query:
SET #last_task = 0;
SELECT
IF(#last_task = RobotShortestPath, 0, 1) AS new_task,
#last_task := RobotShortestPath
FROM rob_log
ORDER BY rog_log_id;
1 1456
0 1456
0 1456
1 1234
0 1234
1 1456
1 2556
1 1456
sum query
SET #last_task = 0;
SELECT SUM(new_task) AS tasks_performed
FROM (
SELECT
IF(#last_task = RobotShortestPath, 0, 1) AS new_task,
#last_task := RobotShortestPath
FROM rob_log
ORDER BY rog_log_id
) AS tmp
4
table structure
CREATE TABLE rob_log (
rog_log_id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
# RobotPosX FLOAT NOT NULL,
# RobotPosY FLOAT NOT NULL,
# RobotPosDir TINYINT UNSIGNED NOT NULL,
RobotShortestPath MEDIUMINT UNSIGNED NOT NULL,
PRIMARY KEY(rog_log_id),
KEY (rog_log_id, RobotShortestPath)
);
INSERT INTO rob_log(RobotShortestPath) SELECT 1456;
INSERT INTO rob_log(RobotShortestPath) SELECT 1456;
INSERT INTO rob_log(RobotShortestPath) SELECT 1456;
INSERT INTO rob_log(RobotShortestPath) SELECT 1234;
INSERT INTO rob_log(RobotShortestPath) SELECT 1234;
INSERT INTO rob_log(RobotShortestPath) SELECT 1456;
INSERT INTO rob_log(RobotShortestPath) SELECT 2556;
INSERT INTO rob_log(RobotShortestPath) SELECT 1456;
testing it at sqlfiddle: http://sqlfiddle.com/#!2/e80f5/3
as an answer for Counting changes in timeline with MySQL
but got relly confused
Here's the reason (as discussed on Twitter):
The variable #last_task was defined in a separate query "batch". I break up the queries on SQL Fiddle into individual batches, executed separately. I do this so you can see the output from each batch as a distinct result set below. In your Fiddle, you can see that there are two sets of output: http://sqlfiddle.com/#!2/e80f5/3/0 and http://sqlfiddle.com/#!2/e80f5/3/1. These map to the two statements you are running (the set and the select). The problem is, your set statement defines a variable that only exists in the first batch; when the select statement runs, it is a separate batch and your variable isn't defined within that context.
To correct this problem, all you have to do is define a different query terminator. Note the dropdown box/button under both the schema and the query panels ( [ ; ] ) - click on that, and you can choose something other than semicolon (the default). Then your two statements will be included together as part of the same batch, and you'll get the result you want. For example:
http://sqlfiddle.com/#!2/e80f5/9
It's probably a some bug in older version of MySQL.
I have tried it on MySQL 5.5 and its working perfectly.

MySQL INSERT Using Subquery with COUNT() on the Same Table

I'm having trouble getting an INSERT query to execute properly, and I can't seem to find anything on Google or Stack Overflow that solves this particular issue.
I'm trying to create a simple table for featured entries, where the entry_id is saved to the table along with it's current order.
My desired output is this:
If the featured table currently has these three entries:
featured_id entry_id featured_order
1 27 0
2 54 1
4 23 2
I want the next entry to save with featured_order=3.
I'm trying to get the following query to work with no luck:
INSERT INTO `featured`
(
`entry_id`, `featured_order`
)
VALUES
(
200,
(SELECT COUNT(*) AS `the_count` FROM `featured`)
)
The error I'm getting is: You can't specify target table 'featured' for update in FROM clause.
Can anyone help with a solution that gets the count without causing an error?
Thanks in advance!
Here is a cool thing: MySQL's INSERT . . . SELECT:
INSERT INTO `featured`
(
`entry_id`, `featured_order`
)
SELECT 200, COUNT(*) + 1
FROM `featured`
No subquery required.
#Bohemian has a good point:
Better to use max(featured_order) + 1 if you use this approach
So a better query would probably be:
INSERT INTO `featured`
(
`entry_id`, `featured_order`
)
SELECT 200, MAX(`featured_order`) + 1
FROM `featured`
His trigger method describe in his answer is also a good way to accomplish what you want.
The potential problem with query 1 is if you ever delete a row the rank will be thrown off, and you'll have a duplicate in featured_order. With the second query this is not a problem, but you will have gaps, just as if you were using an auto-increment column.
If you absolutely must have an order with no gaps the best solution I know of is to run this series of queries:
SET #pos:=0;
DROP TABLE IF EXISTS temp1;
CREATE TEMPORARY TABLE temp1 LIKE featured;
ALTER TABLE featured ORDER BY featured_order ASC;
INSERT INTO temp1 (featured_id, entry_id, featured_order)
SELECT featured_id, entry_id, #pos:=#pos+1 FROM words;
UPDATE featured
JOIN temp1 ON featured.featured_id = temp1.featured_id
SET featured.rank = temp1.rank;
DROP TABLE temp1;
Whenever you delete a row
Use a trigger:
drop trigger if exists featured_insert_trigger;
delimiter //
create trigger featured_insert_trigger before insert on featured
for each row
begin
set new.featured_order = ifnull((select max(featured_order) from featured), -1) + 1;
end; //
delimiter ;
Now your inserts look like this:
insert into featured (entry_id) values (200);
featured_order will be set to the highest featured_order value plus one. This caters for rows being deleted/updated and always guarantee uniqueness.
The ifnull is there in case there are no rows in the table, in which case the first value will be zero.
This code has been tested as works correctly.
INSERT INTO `featured`
(
`entry_id`, `featured_order`
)
VALUES
(
200,
(SELECT COUNT(*) AS `the_count` FROM `featured` F1)
)
Correction is just adding "F1" table alias.
This standard sql solution works fine on various dbms (not only mysql)
I also suggest an improvement over:
SELECT COUNT(*) +1 (Problem: if some row gets deleted you may collide with existing index)
SELECT MAX(featured_order)+1 (Problem: the first insert with empty table gets error)
SELECT (COALESCE(MAX(featured_order), 0)+1) (no Problem)
You have to simpley use alias that will solve the problem :
INSERT INTO `featured`
(
`entry_id`, `featured_order`
)
VALUES
(
200,
(SELECT COUNT(*) AS `the_count` FROM `featured` as f1)
)
From the MySQL manual regarding subqueries:
Another restriction is that currently you cannot modify a table and select from the same table in a subquery.
Perhaps an alias or a join (otherwise useless) in the subquery would help here.
EDIT: It turns out that there's a work-around. The work-around is described http://www.xaprb.com/blog/2006/06/23/how-to-select-from-an-update-target-in-mysql/.