sql min function and other column for sqlite - mysql

For sqlite I see that such query return correct result:
CREATE TABLE users(id INTEGER PRIMARY KEY,
user_id INTEGER NOT NULL,
salary INTEGER NOT NULL);
insert into users (user_id, salary) values (1, 42000);
insert into users (user_id, salary) values (2, 39000);
insert into users (user_id, salary) values (3, 50000);
sqlite> SELECT user_id, MAX(salary) FROM users;
3|50000
sqlite> SELECT user_id, MIN(salary) FROM users;
2|39000
but looks like for mysql for example works in other way:
sql min function and other column
and return 1|50000.
Is it sqlite extension or may be mysql wrong in this case and this standard behaviour for SQL implementation?

The result is not "correct" in SQLite. SQLite extends its functionality to support these types of non-standard queries. This is clearly an extension of functionality, and one I wish it did not do.
The queries are non-standard because there is an unaggregated column in the SELECT (id) but the query is an aggregation query (because of the MIN()/MAX()). The more recent versions of MySQL with the default settings correctly reject this query as not syntactically correct. Older versions of MySQL return a value of id from an arbitrary row. SQLite has extended the definition of SQL for this special case and brings back the value of id that corresponds to the maximum or minimum salary.
In both databases, the better approach is:
SELECT user_id, salary as max_salary
FROM users
ORDER BY salary DESC
LIMIT 1;
and:
SELECT user_id, salary as min_salary
FROM users
ORDER BY salary ASC
LIMIT 1;

Related

How to use SELECT MAX inside an INSERT statement in MySQL?

Short Version:
How can I get the maximum value of a column and use the result when adding a row with INSERT INTO statement?
Long Version:
I have read the question: How to use 'select ' in MySQL 'insert' statement and tried to follow the instructions for its answers. This is my query:
INSERT INTO employee (id, name, state, supervisorId) SELECT MAX(id)+1, 'Dan', state, supervisorId FROM employee WHERE name='Chris';
But I get this error:
ERROR: 1062: Duplicate entry '7' for key 'PRIMARY'
The reason is that I have another row whose id is 7. Consequently,
MAX(id)
doesn't return the actual maximum value, but a value equal to id of the row containing 'Chris' which is 6.
What am I doing wrong?
You can fix it by replacing this:
MAX(id)+1
with this select query:
(SELECT MAX(id)+1 FROM employee)
Here's the complete query:
INSERT INTO employee (id, name, state, supervisorId) SELECT (SELECT MAX(id)+1 FROM employee), 'Dan', state, supervisorId FROM employee WHERE name='Chris';
Update:
Although this answer solves the general question about getting the SELECT MAX inside an INSERT query, as #RaymondNijland suggested, it's better to make the most of MySQL auto_increment functionalities. To do so:
1) Make your primary key column, auto incremented:
ALTER TABLE employee MODIFY COLUMN id INT NOT NULL AUTO_INCREMENT;
2) Remove the id from your insert query:
INSERT INTO employee (name, state, supervisorId) SELECT 'Dan', state, supervisorId FROM employee WHERE name='Chris';
Using manual increment on SQL queries can lead to race conditions.
You should have the AI (auto increment) constraint when you create your table PK (Primary Key).
CREATE TABLE table_name
(
table_id int NOT NULL PRIMARY KEY AUTO INCREMENT,
....
);
If you absolutely have to use manual increment, use SELECT statement.

Getting the last inserted ID with expression in mysql

I want to get the value of the last id insert in a table. How i can do this in mysql?
For eg : in db2 we have
SET var_ID = (SELECT ID FROM NEW TABLE (INSERT INTO val_CLIENT(E_VER, NAME, TYPE) VALUES(0, val_NAME, 502)));
The above statement needs to be converted into mysql. How can i do this?
You can use the LAST_INSERT_ID() function.
Do your insert statement:
INSERT INTO val_CLIENT(E_VER, NAME, TYPE) VALUES(0, val_NAME, 502);
Depending if you're doing it in a stored procedure, you will have to modify this, but if you're looking to select it.
SELECT LAST_INSERT_ID() AS `ID`;
To store it as a variable, you can use the SET statement.
SET #VarID = (SELECT LAST_INSERT_ID());
If your ID column is of type AUTO_INCREMENT, Use LAST_INSERT_ID() after the INSERT statement
SELECT LAST_INSERT_ID() as ID
However, for concurrent requests using same connection, this will lead into inconsistent result. In that case, the following query is a safe bet:
SELECT ID FROM val_CLIENT
ORDER BY ID DESC
LIMIT 1
A possible query:
SELECT id FROM tableORDER BY id DESC LIMIT 1

error with IF EXISTS ()

IF NOT EXISTS (SELECT 1 FROM Products WHERE name='Iphone1' AND manufacturer='appl') THEN
INSERT INTO Products(product_id, name, category, manufacturer)
VALUES (10000, 'IphoneZ', null, 'appl');
ERROR: syntax error at or near "IF" LINE 1: IF NOT EXISTS (SELECT 1
FROM Products WHERE name='Iphone1' A...
Can anyone help me understand what I am doing wrong?
MySQL only supports the IF statement in programming blocks -- stored procedures, functions, and triggers. Hence you cannot do what you want that way.
Instead, you can just write a single query:
INSERT INTO Products (product_id, name, category, manufacturer)
SELECT product_id, name, category, manufacturer
FROM (SELECT 10000 as product_id, 'IphoneZ' as name, null as category, 'appl' as manufacturer) t
WHERE NOT EXISTS (SELECT 1 FROM Products p WHERE p.name = t.name and p.manufacturer = t.manufacturer);
Actually, though, it is best to have the database directly enforce this sort of uniqueness. You can do so with a unique constraint/index:
CREATE UNIQUE INDEX unq_product_manufacturer_name ON product(manufacturer, name);
Then you can write an query to ignore errors by doing:
INSERT INTO Products (product_id, name, category, manufacturer)
VALUES (10000, 'IphoneZ', null, 'appl')
ON DUPLICATE KEY UPDATE category = VALUES(category);
The ON DUPLICATE KEY doesn't do anything -- it just serves to avoid returning an error if a duplicate value is inserted.
You are missing END IF keyword at the end of IF statement. And also, this SQL statement can be only used in a Routine block such as Stored Procedure or Stored Function.
Your SQL should be like this:
IF NOT EXISTS (SELECT 1 FROM Products WHERE name='Iphone1' AND manufacturer = 'appl') THEN
INSERT INTO Products(product_id, name, category, manufacturer)
VALUES (10000, 'IphoneZ', null, 'appl');
END IF;
Is it MySQL or SQL server?
I think you type wrongly : name='Iphone1' . It should be 'IphoneZ'.
You used single quotes in some places and double quotes in some places.
If it is mysql then try below query
INSERT INTO Products(product_id, name, category, manufacturer)
SELECT * FROM (select 10000,'IphoneZ', null, 'appl') AS tmp_table
WHERE NOT EXISTS (SELECT 1 FROM Products_arun WHERE name='IphoneZ'
AND manufacturer='appl') LIMIT 1;
If it is SQL server then try below query
IF NOT EXISTS (SELECT 1 FROM product WHERE name='IphoneZ' AND manufacturer='appl')
INSERT INTO product(product_id, name, category, manufacturer)
VALUES (10000, 'IphoneZ', null, 'appl');

How Group By works with Duplicates

I am trying to get some insight as to how some SQL statements work. Right know I am looking into GROUP BY and want to know, how does it choose what to show/return with duplicate data.
Consider the following example:
CREATE TABLE customers
(
FirstName VARCHAR(50),
LastName VARCHAR(50),
MobileNo VARCHAR(15)
);
INSERT INTO customers VALUES ('Niraj','Yadav',989898);
INSERT INTO customers VALUES ('Chetan','Gadodia',959595);
INSERT INTO customers VALUES ('Chetan','Gadodia',959590);
INSERT INTO customers VALUES ('Atul','Kokam',42424242);
INSERT INTO customers VALUES ('Atul','Kokam',42424246);
INSERT INTO customers VALUES ('Vishal','Parte',9394452);
INSERT INTO customers VALUES ('Vishal','Parte',939445);
INSERT INTO customers VALUES ('Vishal','Parte',9394451);
INSERT INTO customers VALUES ('Jinendra','Jain',12121);
INSERT INTO customers VALUES ('Jinendra','Jain',121212);
If I run this query...
SELECT *
FROM customers
GROUP BY FirstName;
I get the following results:
FirstName LastName MobileNo
--------- -------- ----------
Atul Kokam 42424242
Chetan Gadodia 959595
Jinendra Jain 12121
Niraj Yadav 989898
Vishal Parte 9394452
So, my question is: is there any reason why it returns these particular records? How does it determine what to get? I'm using MySQL.
In other databases, your query would not be allowed exactly because the results are unpredictable in this case.
Notice what the MySQL documentation has to say for this case:
MySQL Handling of GROUP BY
The server is free to choose any value from each group, so unless they are the same, the values chosen are indeterminate.
I should also mention, that Gordon Linoff recently pointed out to me that, starting in version 5.7 of MySQL, a query like yours, where unpredictable results are possible, will no longer be allowed by default.
Info on that: MySQL 5.7: only_full_group_by Improved, Recognizing Functional Dependencies, Enabled by Default!

Update with Subquery never completes

I'm currently working on a project with a MySQL Db of more than 8 million rows. I have been provided with a part of it to test some queries on it. It has around 20 columns out of which 5 are of use to me. Namely: First_Name, Last_Name, Address_Line1, Address_Line2, Address_Line3, RefundID
I have to create a unique but random RefundID for each row, that is not the problem. The problem is to create same RefundID for those rows whose First_Name, Last_Name, Address_Line1, Address_Line2, Address_Line3 as same.
This is my first real work related to MySQL with such large row count. So far I have created these queries:
-- Creating Teporary Table --
CREATE temporary table tempT (SELECT tt.First_Name, count(tt.Address_Line1) as
a1, count(tt.Address_Line2) as a2, count(tt.Address_Line3) as a3, tt.RefundID
FROM `tempTable` tt GROUP BY First_Name HAVING a1 >= 2 AND a2 >= 2 AND a3 >= 2);
-- Updating Rows with First_Name from tempT --
UPDATE `tempTable` SET RefundID = FLOOR(RAND()*POW(10,11))
WHERE First_Name IN (SELECT First_Name FROM tempT WHERE First_Name is not NULL);
This update query keeps on running but never ends, tempT has more than 30K rows. This query will then be run on the main DB with more than 800K rows.
Can someone help me out with this?
Regards
The solutions that seem obvious to me....
Don't use a random value - use a hash:
UPDATE yourtable
SET refundid = MD5('some static salt', First_Name
, Last_Name, Address_Line1, Address_Line2, Address_Line3)
The problem is that if you are using an integer value for the refundId then there's a good chance of getting a collision (hint CONV(SUBSTR(MD5(...),1,16),16,10) to get a SIGNED BIGINT). But you didn't say what the type of the field was, nor how strict the 'unique' requirement was. It does carry out the update in a single pass though.
An alternate approach which creates a densely packed seguence of numbers is to create a temporary table with the unique values from the original table and a random value. Order by the random value and set a monotonically increasing refundId - then use this as a look up table or update the original table:
SELECT DISTINCT First_Name
, Last_Name, Address_Line1, Address_Line2, Address_Line3
INTO temptable
FROM yourtable;
set #counter=-1;
UPDATE temptable t SET t,refundId=(#counter:=#counter + 1)
ORDER BY r.randomvalue;
There are other solutions too - but the more efficient ones rely on having multiple copies of the data and/or using a procedural language.
Try using the following:
UPDATE `tempTable` x SET RefundID = FLOOR(RAND()*POW(10,11))
WHERE exists (SELECT 1 FROM tempT y WHERE First_Name is not NULL and x.First_Name=y.First_Name);
In MySQL, it is often more efficient to use join with update than to filter through the where clause using a subquery. The following might perform better:
UPDATE `tempTable` join
(SELECT distinct First_Name
FROM tempT
WHERE First_Name is not NULL
) fn
on temptable.First_Name = fn.First_Name
SET RefundID = FLOOR(RAND()*POW(10,11));