Syntax error in subquery in mysql - mysql

I am getting a #1064 error from this code I am trying to use a subquery within the values command I am new to mySQL and cannot spot the mistake.
CREATE TEMPORARY TABLE TempTable(myid INT,points INT)
INSERT INTO TempTable
values(1,
points
(
SELECT player.team, COUNT( * ) AS count
FROM playerpoints
JOIN player ON playerpoints.PlayerID = player.PlayerID
WHERE player.team = 'ManU'
AND EXTRACT( MONTH FROM playerpoints.date ) <07
GROUP BY player.team
));
INSERT INTO TempTable
values(2,
points
(
SELECT player.team, COUNT( * ) AS count2
FROM playerpoints
JOIN player ON playerpoints.PlayerID = player.PlayerID
WHERE player.team = 'ManU'
AND EXTRACT( MONTH FROM playerpoints.date ) >07
GROUP BY player.team
));
DROP TABLE TempTable;

The construct you want to use is INSERT INTO ... SELECT .... You don't use a subquery (or the VALUES keyword).
INSERT INTO TempTable (myid, points)
SELECT player.team, COUNT( * ) AS count
FROM playerpoints
JOIN player ON playerpoints.PlayerID = player.PlayerID
WHERE player.team = 'ManU'
AND EXTRACT( MONTH FROM playerpoints.date ) <07
GROUP BY player.team;
Basically, you want the SELECT to return the row(s) you're inserting (in the correct order).
Docs: http://dev.mysql.com/doc/refman/5.0/en/insert-select.html

No semicolon at the end of the first line. Also the INSERT syntax can be cleaned up a bit. Finally, the GROUP BY clause is not needed. Try this:
Try this:
CREATE TEMPORARY TABLE TempTable(myid INT,points INT);
INSERT INTO TempTable
values(1, (
SELECT COUNT( * )
FROM playerpoints
JOIN player ON playerpoints.PlayerID = player.PlayerID
WHERE player.team = 'ManU'
AND EXTRACT( MONTH FROM playerpoints.date ) <07
));
INSERT INTO TempTable
values(2, (
SELECT COUNT( * )
FROM playerpoints
JOIN player ON playerpoints.PlayerID = player.PlayerID
WHERE player.team = 'ManU'
AND EXTRACT( MONTH FROM playerpoints.date ) >07
));
...
DROP TABLE TempTable;
This assumes that playerpoints records one point per entry. Otherwise you'll need something like SELECT SUM(playerpoints.points) instead of SELECT COUNT(*).

Related

Update empty values in column from the same column [duplicate]

I have a simple mysql table:
CREATE TABLE IF NOT EXISTS `pers` (
`persID` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(35) NOT NULL,
`gehalt` int(11) NOT NULL,
`chefID` int(11) DEFAULT NULL,
PRIMARY KEY (`persID`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=4 ;
INSERT INTO `pers` (`persID`, `name`, `gehalt`, `chefID`) VALUES
(1, 'blb', 1000, 3),
(2, 'as', 1000, 3),
(3, 'chef', 1040, NULL);
I tried to run following update, but I get only the error 1093:
UPDATE pers P
SET P.gehalt = P.gehalt * 1.05
WHERE (P.chefID IS NOT NULL
OR gehalt <
(SELECT (
SELECT MAX(gehalt * 1.05)
FROM pers MA
WHERE MA.chefID = MA.chefID)
AS _pers
))
I searched for the error and found from mysql following page http://dev.mysql.com/doc/refman/5.1/en/subquery-restrictions.html, but it doesn't help me.
What shall I do to correct the sql query?
The problem is that MySQL, for whatever inane reason, doesn't allow you to write queries like this:
UPDATE myTable
SET myTable.A =
(
SELECT B
FROM myTable
INNER JOIN ...
)
That is, if you're doing an UPDATE/INSERT/DELETE on a table, you can't reference that table in an inner query (you can however reference a field from that outer table...)
The solution is to replace the instance of myTable in the sub-query with (SELECT * FROM myTable), like this
UPDATE myTable
SET myTable.A =
(
SELECT B
FROM (SELECT * FROM myTable) AS something
INNER JOIN ...
)
This apparently causes the necessary fields to be implicitly copied into a temporary table, so it's allowed.
I found this solution here. A note from that article:
You don’t want to just SELECT * FROM table in the subquery in real life; I just wanted to keep the examples simple. In reality, you should only be selecting the columns you need in that innermost query, and adding a good WHERE clause to limit the results, too.
You can make this in three steps:
CREATE TABLE test2 AS
SELECT PersId
FROM pers p
WHERE (
chefID IS NOT NULL
OR gehalt < (
SELECT MAX (
gehalt * 1.05
)
FROM pers MA
WHERE MA.chefID = p.chefID
)
)
...
UPDATE pers P
SET P.gehalt = P.gehalt * 1.05
WHERE PersId
IN (
SELECT PersId
FROM test2
)
DROP TABLE test2;
or
UPDATE Pers P, (
SELECT PersId
FROM pers p
WHERE (
chefID IS NOT NULL
OR gehalt < (
SELECT MAX (
gehalt * 1.05
)
FROM pers MA
WHERE MA.chefID = p.chefID
)
)
) t
SET P.gehalt = P.gehalt * 1.05
WHERE p.PersId = t.PersId
In Mysql, you can not update one table by subquery the same table.
You can separate the query in two parts, or do
UPDATE TABLE_A AS A
INNER JOIN TABLE_A AS B ON A.field1 = B.field1
SET field2 = ?
Make a temporary table (tempP) from a subquery
UPDATE pers P
SET P.gehalt = P.gehalt * 1.05
WHERE P.persID IN (
SELECT tempP.tempId
FROM (
SELECT persID as tempId
FROM pers P
WHERE
P.chefID IS NOT NULL OR gehalt <
(SELECT (
SELECT MAX(gehalt * 1.05)
FROM pers MA
WHERE MA.chefID = MA.chefID)
AS _pers
)
) AS tempP
)
I've introduced a separate name (alias) and give a new name to 'persID' column for temporary table
It's quite simple. For example, instead of writing:
INSERT INTO x (id, parent_id, code) VALUES (
NULL,
(SELECT id FROM x WHERE code='AAA'),
'BBB'
);
you should write
INSERT INTO x (id, parent_id, code)
VALUES (
NULL,
(SELECT t.id FROM (SELECT id, code FROM x) t WHERE t.code='AAA'),
'BBB'
);
or similar.
The Approach posted by BlueRaja is slow I modified it as
I was using to delete duplicates from the table. In case it helps anyone with large tables
Original Query
DELETE FROM table WHERE id NOT IN (SELECT MIN(id) FROM table GROUP BY field 2)
This is taking more time:
DELETE FROM table WHERE ID NOT IN(
SELECT MIN(t.Id) FROM (SELECT Id, field2 FROM table) AS t GROUP BY field2)
Faster Solution
DELETE FROM table WHERE ID NOT IN(
SELECT t.Id FROM (SELECT MIN(Id) AS Id FROM table GROUP BY field2) AS t)
MySQL doesn't allow selecting from a table and update in the same table at the same time. But there is always a workaround :)
This doesn't work >>>>
UPDATE table1 SET col1 = (SELECT MAX(col1) from table1) WHERE col1 IS NULL;
But this works >>>>
UPDATE table1 SET col1 = (SELECT MAX(col1) FROM (SELECT * FROM table1) AS table1_new) WHERE col1 IS NULL;
MariaDB has lifted this starting from 10.3.x (both for DELETE and UPDATE):
UPDATE - Statements With the Same Source and Target
From MariaDB 10.3.2, UPDATE statements may have the same source and target.
Until MariaDB 10.3.1, the following UPDATE statement would not work:
UPDATE t1 SET c1=c1+1 WHERE c2=(SELECT MAX(c2) FROM t1);
ERROR 1093 (HY000): Table 't1' is specified twice,
both as a target for 'UPDATE' and as a separate source for data
From MariaDB 10.3.2, the statement executes successfully:
UPDATE t1 SET c1=c1+1 WHERE c2=(SELECT MAX(c2) FROM t1);
DELETE - Same Source and Target Table
Until MariaDB 10.3.1, deleting from a table with the same source and target was not possible. From MariaDB 10.3.1, this is now possible. For example:
DELETE FROM t1 WHERE c1 IN (SELECT b.c1 FROM t1 b WHERE b.c2=0);
DBFiddle MariaDB 10.2 - Error
DBFiddle MariaDB 10.3 - Success
Just as reference, you can also use Mysql Variables to save temporary results, e.g.:
SET #v1 := (SELECT ... );
UPDATE ... SET ... WHERE x=#v1;
https://dev.mysql.com/doc/refman/5.7/en/user-variables.html
If you are trying to read fieldA from tableA and save it on fieldB on the same table, when fieldc = fieldd you might want consider this.
UPDATE tableA,
tableA AS tableA_1
SET
tableA.fieldB= tableA_1.filedA
WHERE
(((tableA.conditionFild) = 'condition')
AND ((tableA.fieldc) = tableA_1.fieldd));
Above code copies the value from fieldA to fieldB when condition-field met your condition. this also works in ADO (e.g access )
source: tried myself
Other workarounds include using SELECT DISTINCT or LIMIT in the subquery, although these are not as explicit in their effect on materialization. this worked for me
as mentioned in MySql Doc

Insert into a table from multiple table(MySql)

insert ignore into user_login_history
(`created_at`,`updated_at`,`created_by`,
`updated_by`,`USER_ID`,`TENANT`,
`LAST_LOGIN`,`deleted`,`published`)
values(
(SELECT
a.created_at,
a.updated_at,
a.created_by,
a.updated_by,
user.id,
a.tenant,
a.created_at,
b'0',
b'1'
FROM
(SELECT audit_log_summary.*
FROM audit_log_summary, (SELECT
user, MAX(created_at) AS created_at, tenant
FROM
audit_log_summary
WHERE
audit_log_summary.REVISION_TYPE = 'LOGGED_IN'
GROUP BY user , TENANT) max_user
WHERE
audit_log_summary.user = max_user.user
AND audit_log_summary.tenant = max_user.tenant
AND audit_log_summary.created_at = max_user.created_at) a
INNER JOIN
user ON a.user = user.email));
error i am getting :
Error Code: 1136. Column count doesn't match value count at row 1
basically I have 3 tables i want to populate data in one table fetching the data from other two..
Table to be populated: user_login_history
Tables From which datas are fetched: audit_log_summary & user
You have to remove VALUES from the clause, so instead of using INSERT INTO VALUES, use INSERT INTO SELECT FROM. Maybe SELECT audit_log_summary.* you should select the needed columns only. In your select you are selecting a.created_at twice, check if it is what you want.
Maybe this will help:
insert ignore into user_login_history (`created_at`,
`updated_at`,
`created_by`,
`updated_by`,
`USER_ID`,
`TENANT`,
`LAST_LOGIN`,
`deleted`,
`published`)
(SELECT
a.created_at,
a.updated_at,
a.created_by,
a.updated_by,
user.id,
a.tenant,
a.created_at,
b'0',
b'1'
FROM
(SELECT audit_log_summary.*
FROM audit_log_summary, (SELECT
user, MAX(created_at) AS created_at, tenant
FROM
audit_log_summary
WHERE
audit_log_summary.REVISION_TYPE = 'LOGGED_IN'
GROUP BY user , TENANT) max_user
WHERE
audit_log_summary.user = max_user.user
AND audit_log_summary.tenant = max_user.tenant
AND audit_log_summary.created_at = max_user.created_at) a
INNER JOIN
user ON a.user = user.email));

SQL Where Not Exists not working

I have two tables called TEMPDATA and Product. I am dumping all my data from a csv feed into TEMPDATA and then organising it into the respective tables, Product being one of them.
I am trying to insert all the contents of TEMPDATA that does not have a duplicate 'ean' number into Product, providing it doesn't already exist in Product.
The query I am trying to use is below...
INSERT IGNORE INTO `Product` (`product_ean`, `product_name`, `product_description`, `product_image`, `product_thumbnail`, `product_category`)
SELECT `ean`, `product_name`, `description`, `merchant_image_url`, `aw_thumb_url`, `merchant_category`
FROM (
SELECT `ean`, `product_name`, `description`, `merchant_image_url`, `aw_thumb_url`, `merchant_category`, count( * )
FROM TEMPDATA
GROUP BY `ean`
HAVING count( * ) = 1
) AS t
WHERE NOT EXISTS (
SELECT `product_ean` FROM Product
)
All the individual sections seem to be working, except from when I include the 'WHERE NOT EXISTS' clause, could someone please help me out?
try this:
INSERT IGNORE INTO Product (product_ean, product_name, product_description, product_image, product_thumbnail, product_category)
SELECT ean, product_name, description, merchant_image_url, aw_thumb_url, merchant_category
FROM (
SELECT ean, product_name, description, merchant_image_url, aw_thumb_url, merchant_category, count( * )
FROM TEMPDATA
GROUP BY ean
HAVING count( * ) = 1
) AS t
WHERE NOT EXISTS (
SELECT product_ean FROM Product AS A WHERE A.product_ean = t.product_name
)
you were missing this:
WHERE A.product_ean = t.product_name
in the NOT EXIST statement
you need to make you include the the where clause to search, see below
INSERT IGNORE INTO `Product` (`product_ean`, `product_name`, `product_description`, `product_image`, `product_thumbnail`, `product_category`)
SELECT `ean`, `product_name`, `description`, `merchant_image_url`, `aw_thumb_url`, `merchant_category`
FROM (
SELECT `ean`, `product_name`, `description`, `merchant_image_url`, `aw_thumb_url`, `merchant_category`, count( * )
FROM TEMPDATA
GROUP BY `ean`
HAVING count( * ) = 1
) AS t
WHERE NOT EXISTS (
SELECT `product_ean` FROM Product P where t.ean = p.`product_ean`
)

insert into table(var1) select from itself

I want to insert into the last column (number of people in that room) and
I want to use
insert into table(n_people_in_room)
select count(people_id)
from table
group by room
This is obvious wrong because i need to join the table with itself on people_id but i didn't. What is the right code?
Here's one way to do it, using an inline view to get the N_People_In_Room totals:
I'd do it as a SELECT first:
SELECT t.peopleid
, t.room
, t.n_people_in_room AS `old_npir`
, s.n_people_in_room AS `new_npir`
FROM mytable t
JOIN ( SELECT c.room
, COUNT(1) AS n_people_in_room
FROM mytable c
GROUP BY c.room
) s
ON s.room = t.room
Convert that into an UPDATE by repacing SELECT ... FROM with UPDATE, and adding a SET clause...
UPDATE mytable t
JOIN ( SELECT c.room
, COUNT(1) AS n_people_in_room
FROM mytable c
GROUP BY c.room
) s
ON s.room = t.room
SET t.n_people_in_room = s.n_people_in_room

How do I rewrite this MySQL query so it doesn't throw this error: You can't specify target table 'crawlLog' for update in FROM clause?

I'm trying to get an id from a companies table where the id is not yet in the crawlLog table. Then I need to insert that companyId into the crawlLog table.
I need to do this in one call so that parallel crawlers don't pull the same url after some other crawler has selected a url, but hasn't inserted it into the crawl log yet. I don't want to lock tables because of other problems that generates.
I get this error from both queries below:
You can't specify target table 'crawlLog' for update in FROM clause
Here are two queries i've tried to do the same thing.
INSERT INTO crawlLog (companyId, timeStartCrawling)
VALUES
(
(
SELECT companies.id FROM companies
LEFT OUTER JOIN crawlLog
ON companies.id = crawlLog.companyId
WHERE crawlLog.companyId IS NULL
LIMIT 1
),
now()
)
I've also tried this, but get the same error:
INSERT INTO crawlLog (companyId, timeStartCrawling)
VALUES
(
(
SELECT id
FROM companies
WHERE id NOT IN
(
SELECT companyId
FROM crawlLog
)
LIMIT 1
),
now()
)
Why use a Subselect? INSERT INTO ... SELECT exists:
INSERT INTO crawlLog (companyId, timeStartCrawling)
SELECT companies.id, NOW()
FROM companies
LEFT OUTER JOIN crawlLog
ON companies.id = crawlLog.companyId
WHERE crawlLog.companyId IS NULL
LIMIT 1
And that way it should not complain about using a table both in the INSERT and SELECT part
You can't update rows which you are querying. There is a way to force MySQL to use a temporary table implicitly:
INSERT INTO crawlLog (companyId, timeStartCrawling)
VALUES
(
SELECT id, when FROM
(
SELECT companies.id AS id, now() AS when FROM companies
LEFT OUTER JOIN crawlLog
ON companies.id = crawlLog.companyId
WHERE crawlLog.companyId IS NULL
LIMIT 1
)
)
This works and seems like the simplest solution:
Using the simpler of the two statements in my question, I created an alias for the inner crawlLog table as suggested by #Tocco in the comments, and then removed the necessary encapsulation in VALUES().
INSERT INTO crawlLog (companyId, timeStartCrawling)
SELECT id, now()
FROM companies
WHERE id NOT IN
(
SELECT companyId
FROM crawlLog AS crawlLogAlias
)
LIMIT 1
Do the select into a temp table, then insert selecting from the temp table. You can't insert into a table and select from it in the same statement, so use a temp table and two statements.