MySQL UPSERT not recognizing alias - mysql

I have a query that performs an UPSERT (Insert - but if exists, update).
MySQL complains it isn't valid, here is the query:
insert into
mytable (user_id, num_products_observed, num_purchased_percent)
(select
A.user_id,
B.total 'num_products_observed',
case
when A.purchased is null then 0
else A.purchased/B.total
end 'num_purchased_percent'
from
(select user_id, count(prod_observed) 'total' from products where user_id = ? ) B
left join (select user_id, count(prod_purch) 'purchased' from products_purchased) A on B.user_id = A.user_id
) newsum -- <--- ISSUE IS HERE
ON DUPLICATE KEY UPDATE
num_products_observed = newsum.num_products_observed,
num_purchased_percent = newsum.num_purchased_percent
I hope this makes sense to you. The issue is at the line which reads ) newsum. MySql complains about the alias I'm giving the table. user_id is unique in this table (mytable).
It IS possible that B.total is null, in which case everything in newsum is null - which is fine, then I don't want to insert or update anything (or an update with user_id and zeros for all would be fine too).
Any thoughts on what I'm doing wrong? Thanks

Are you trying to use VALUES statements.
You can use the VALUES(col_name) function in the UPDATE clause to refer to column values from the INSERT portion of the INSERT ... ON DUPLICATE KEY UPDATE statement
dev.mysql

Related

Multiple conditions on a temporary table - MySQL

I have a temporary table called 'tempaction'. I wanted to select rows where 'ActionID' matches that of another table. I got the safe update mode error, I think as ActionID is part of a compound primary key. However, when I try
UPDATE action
SET Status = 'Sent'
WHERE ActionID IN( select ActionID from tempaction)
AND DeviceID IN( select DeviceID from tempaction);
I get temporary table cannot be reopened error.
Checking both parts of primary key has worked for the safe update error in the past. I also understand that I cannot reference a temporary table twice in the same statement.
How can I select rows with matching ActionID's or matching ActionID's AND DeviceID's from this temporary table?
Tempory Table
CREATE TEMPORARY TABLE tempaction (ActionID BIGINT)
SELECT *
FROM action
WHERE DeviceID = '1234'
AND Status = 'Pending'
You can try Update using Join with sub-query.
UPDATE action a
JOIN
tempaction t ON a.ActionID = t.ActionID
SET
a.Status = 'Sent';

insert into select on duplicate mysql query

I am trying to update on duplicate record in MySQL,
I have a table with many column but i want to update only some column from another table with same desc as current table but it is not updating records.
my query is:
insert into backup_prochart.symbol_list(ticker,end_date,cur_date)
select ticker,t.end_date,t.cur_date from prochart.symbol_list t where
ticker=t.ticker and ticker= 'MAY17' on duplicate key update
end_date=t.end_date,cur_date=t.cur_date;
another query i tried
insert into backup_prochart.symbol_list(ticker,end_date,cur_date) select t.ticker,t.end_date,t.cur_date from prochart.symbol_list t where ticker=t.ticker and t.ticker= 'MAY17' on duplicate key update end_date=t.end_date,cur_date=t.cur_date;
can anyone tell me whats wrong with my query.?
You could try :
INSERT INTO backup_prochart.symbol_list (ticker, end_date, cur_date)
SELECT ticker, end_date, cur_date FROM prochart.symbol_list WHERE ticker = 'MAY17'
ON DUPLICATE KEY UPDATE end_date = values(end_date), cur_date = values(cur_date);
Of course the column "ticker" must be defined as unique for the table "backup_prochart.symbol_list".
You say that you are trying to update a record, but you are using an INSERT statement. Shouldn't you be using UPDATE instead of INSERT?
Difference between INSERT and UPDATE can be found here
Note that you can use UPDATE and SELECT in a single query.
try this. its worked for me.
INSERT INTO employee_projects
(employee_id,
proj_ref_code)
SELECT ep.employee_id,
ep.proj_ref_code
FROM hs_hr_emp_projects_history ep
WHERE NOT EXISTS (SELECT 1
FROM employee_projects p
WHERE ep.employee_id = p.employee_id
AND ep.proj_ref_code = p.proj_ref_code)

How do I combine multiple conditions (exists and not exists) checks before inserting a new record in mysql?

I would like to build a query to insert a new record, after checking with an EXISTS and a NOT EXISTS condition in two different tables.
IF NOT EXISTS (SELECT 1 FROM `categories` WHERE categories.term_id = 123)
AND EXISTS (SELECT 1 FROM `terms` WHERE terms.id = 123)
THEN INSERT INTO `categories`(id, term_id, term_type_id)
VALUES ('', '123', '4')
Thanks in advance.
You an use indices to enforce this behavior.
EXISTS (SELECT 1 FROMtermsWHERE terms.id = 123)
To enforce this, define categories.term_id as a foreign key to terms.id.
That way you can not insert a term_id into the categories table if that is non existent in the terms table.
IF NOT EXISTS (SELECT 1 FROMcategoriesWHERE categories.term_id = 123)
To enforce this, you need to put a UNIQUE index on the categories.term_id column. This will block duplicate entries.
You can first check the desired record from the table with a select query. If the query returns the 0 rows then execute the insert statement otherwise no need to insert.

INSERT if related row does not exist

INSERT IGNORE doesn't work because there won't actually be a key conflict.
This is for a progress queue. For one application I don't want two rows with status S (for "started"). However other applications should be able to - in particular if I want to force two work items to happen at once, I can. So that's why it's not a database constraint.
So it's a little tricky to say in SQL "insert where does not exist." This works:
insert into user_queue_google
(user_id, status, start_timestamp)
(select 221, 'S', NOW() FROM filter_type
WHERE 221 not in (select user_id from user_queue_google where status = 'S') limit 1);
The problem is filter_type is a completely unrelated table that I just know is small and happens to never be empty. If it were empty for some reason, this would fail.
Can I avoid this very horrible hack without resorting to stored programs or IF/THEN logic in my SQL program?
use the dual system dummy table
insert into user_queue_google (user_id, status, start_timestamp)
select 221, 'S', NOW()
from dual
WHERE not exists
(
select user_id
from user_queue_google
where status = 'S'
and user_id = 221
)
You are permitted to specify DUAL as a dummy table name in situations where no tables are referenced
Source
You need to have a UNIQUE index for INSERT IGNORE to work effectively. What you could do is add an additional column that defaults to something harmless but could be changed to unique the key:
CREATE UNIQUE INDEX index_block ON user_queue_google (user_id, force);
Set force as a column that has DEFAULT 0. If you want to force two jobs to run at the same time, set it to something else to avoid a conflict:
UPDATE user_queue_google SET status='S', force=UNIX_TIMESTAMP() WHERE user_id=221
That'll free up a new slot for inserting new jobs.
This should work:
insert into user_queue_google
(user_id, status, start_timestamp)
select
A.user_id,
A.status,
A.start_timestamp
FROM
(SELECT
221 user_id,
'S' status,
NOW() start_timestamp) AS A
LEFT JOIN user_queue_google ON A.user_id = user_queue_google.user_id AND A.status = user_queue_google.status
WHERE
user_queue_google.user_id IS NULL;
See attached fiddle Insert if row doesn't exist

Insert into... select from.... query with where condition

I want make sql query which will insert values from one table to another table by checking where condition on 1st table.
I have to check is that row present previously in 1st table or not. If not present then add otherwise don't add.
There is query "insert into select from" pattern in sql.
I have tried following query. But it inserts many duplicates.
INSERT INTO
company_location (company_id, country_id, city_id)
SELECT
ci.company_id, hq_location, hq_city
FROM
company_info ci, company_location cl
WHERE
ci.company_id <> cl.company_id
AND cl.country_id <> ci.hq_location
AND cl.city_id <> ci.hq_city;
Duplicate avoiding means that tuple (company_id, country_id, city_id) shouldn't added again. And I have to add from more 4 tables into these table.
Also I require query for removing duplicates from company_location. i.e. combination of (company_id, country_id, city_id) should exist only single time. Keep only one tuple and remove other rows.
I hope this untested Script helps! It inserts every combination just once.
INSERT INTO company_location
(company_id,country_id,city_id)
SELECT distinct ci.company_id,
ci.hq_location,
ci.hq_city
FROM company_info ci
WHERE ci.company_id NOT IN
(SELECT cl1.company_id FROM company_location cl1
WHERE cl1.country_id = ci.hq_location
AND cl1.city_id = ci.hq_city
AND cl1.company_id = ci.company_id)
INSERT INGORE works.
If you want a column (or column set) to be unique, put a UNIQUE constraint on your table. If yu no have UNIQUE CONSTRAINT, therefore, by definition, the table cannot contain any undesirable duplicates, since not putting a UNIQUE constraint means duplicates are desirable.
Add UNIQUE( company_id,country_id,city_id )(or maybe it's your primary key for that table)
use INSERT IGNORE
You can also rewrite your query correctly. The query does not do what you think it does, and you cannot do what you want by using the old join syntax from the 18th century.
SELECT * FROM t1, t2, t3
Is a CROSS JOIN, this means it takes all possible combinations of rows from table t1,t2,t3. Usually the WHERE contains some "t1.id=t2.id" conditions to restrict it and turn it into an INNER JOIN, but "<>" conditions do not do this...
You need a proper LEFT JOIN :
INSERT INTO company_location (company_id,country_id,city_id)
SELECT ci.company_id, hq_location, hq_city
FROM company_info ci,
LEFT JOIN company_location cl ON (
ci.company_id = cl.company_id
AND cl.country_id = ci.hq_location
AND cl.city_id = ci.hq_city
)
WHERE cl.company_id IS NULL
Here the answer to your second Question; Query to delete duplicate entries:
Please be careful with the statements they are not tested.
Solution 1:
This solution only works, if you have a row-Id in your table.
DELETE FROM company_location
WHERE id NOT IN
(SELECT MAX(cl1.id)
FROM company_location cl1
WHERE cl1.company_id = company_location.company_id
AND cl1.country_id = company_location.country_id
AND cl1.city_id = company_location.city_id)
Solution 2:
This works without row_id. It writes all data into a Temporary table. Deletes the content on the first table. And inserts every tupel just once.
To that solution: Be careful if you have defined constraints on that table!
CREATE TEMPORARY TABLE tmp_company_location
(
company_id bigint
,country_id bigint
,city_id bigint
);
INSERT INTO tmp_company_location
(company_id,country_id,city_id)
SELECT DISTINCT
company_id
,country_id
,city_id
FROM company_location WHERE 1;
DELETE FROM company_location;
INSERT INTO company_location
SELECT DISTINCT
company_id
,country_id
,city_id
FROM tmp_company_location;
use INSERT IGNORE INTO
from Mysql Docs
Specify IGNORE to ignore rows that would cause duplicate-key violations.