What does this MySQL statement do? - mysql

INSERT IGNORE INTO `PREFIX_tab_lang` (`id_tab`, `id_lang`, `name`)
(SELECT `id_tab`, id_lang, (SELECT tl.`name`
FROM `PREFIX_tab_lang` tl
WHERE tl.`id_lang` = (SELECT c.`value`
FROM `PREFIX_configuration` c
WHERE c.`name` = 'PS_LANG_DEFAULT' LIMIT 1) AND tl.`id_tab`=`PREFIX_tab`.`id_tab`)
FROM `PREFIX_lang` CROSS JOIN `PREFIX_tab`);
It's from an opensource project,and no documentation available.
Especially,what does cross-join mean? I've only used join/left join .

According to the MySQL documentation, it's basically a synonym for INNER JOIN, and INNER JOIN is the same as just JOIN (that is, "INNER" is the default).

Cross-join: http://en.wikipedia.org/wiki/Join_%28SQL%29#Cross_join
The query inserts into PREFIX_tab_lang the results of a select. The select is just two columns from the cross-product. The third column -- name -- actually comes from a totally different select, which is also pretty straight-forward except that one of it's where conditions is yet another select.
In short, this is one of the worst queries I've ever seen. It's preformance is probably horrible, and it should be replaced by a bit of TRANSATION-protected code or, at the very least, a stored procedure.

You can actually consider the following queries to be synonyms in MySQL:
SELECT *
FROM Table1
CROSS JOIN Table2;
SELECT *
FROM Table1, Table2;
SELECT *
FROM Table1
INNER JOIN Table2;
SELECT *
FROM Table1
JOIN Table2;
Test Case:
CREATE TABLE Table1 (id int, value varchar(10));
CREATE TABLE Table2 (id int, t1_id int);
INSERT INTO Table1 VALUES (1, 'Value 1');
INSERT INTO Table1 VALUES (2, 'Value 2');
INSERT INTO Table1 VALUES (3, 'Value 3');
INSERT INTO Table1 VALUES (4, 'Value 4');
INSERT INTO Table2 VALUES (1, 1);
INSERT INTO Table2 VALUES (2, 1);
INSERT INTO Table2 VALUES (3, 2);
INSERT INTO Table2 VALUES (4, 2);
INSERT INTO Table2 VALUES (5, 2);
INSERT INTO Table2 VALUES (6, 3);
INSERT INTO Table2 VALUES (7, 4);
INSERT INTO Table2 VALUES (8, 4);
INSERT INTO Table2 VALUES (9, 4);
All four queries would return the following result set:
+------+---------+------+-------+
| id | value | id | t1_id |
+------+---------+------+-------+
| 1 | Value 1 | 1 | 1 |
| 2 | Value 2 | 1 | 1 |
| 3 | Value 3 | 1 | 1 |
| 4 | Value 4 | 1 | 1 |
| 1 | Value 1 | 2 | 1 |
| 2 | Value 2 | 2 | 1 |
| 3 | Value 3 | 2 | 1 |
| 4 | Value 4 | 2 | 1 |
| 1 | Value 1 | 3 | 2 |
| 2 | Value 2 | 3 | 2 |
| 3 | Value 3 | 3 | 2 |
| 4 | Value 4 | 3 | 2 |
| 1 | Value 1 | 4 | 2 |
| 2 | Value 2 | 4 | 2 |
| 3 | Value 3 | 4 | 2 |
| 4 | Value 4 | 4 | 2 |
| 1 | Value 1 | 5 | 2 |
| 2 | Value 2 | 5 | 2 |
| 3 | Value 3 | 5 | 2 |
| 4 | Value 4 | 5 | 2 |
| 1 | Value 1 | 6 | 3 |
| 2 | Value 2 | 6 | 3 |
| 3 | Value 3 | 6 | 3 |
| 4 | Value 4 | 6 | 3 |
| 1 | Value 1 | 7 | 4 |
| 2 | Value 2 | 7 | 4 |
| 3 | Value 3 | 7 | 4 |
| 4 | Value 4 | 7 | 4 |
| 1 | Value 1 | 8 | 4 |
| 2 | Value 2 | 8 | 4 |
| 3 | Value 3 | 8 | 4 |
| 4 | Value 4 | 8 | 4 |
| 1 | Value 1 | 9 | 4 |
| 2 | Value 2 | 9 | 4 |
| 3 | Value 3 | 9 | 4 |
| 4 | Value 4 | 9 | 4 |
+------+---------+------+-------+
36 rows in set (0.01 sec)

Related

How to insert a specify row in mysql?

Suppose I have a table t1 like
mysql> select * from t1;
+------+-------+------+
| id | level | gap |
+------+-------+------+
| 1 | 6 | 50 |
| 1 | 5 | 10 |
| 2 | 5 | 12 |
| 2 | 5 | 10 |
| 3 | 8 | 4 |
| 3 | 9 | 1 |
| 3 | 9 | 3 |
| 3 | 7 | 2 |
+------+-------+------+
I want to insert a row (3,6,7) into here.I mean it is below in first 5 row.
Is it possible in mysql?
Just do
INSERT INTO t1 (id, level,gap) VALUES (3,6,7)
Records in a table do not have a prescribed order. The order has to be defined during a SELECT by supplying a suitable ORDER BY clause.
So, if you want the new record to be listed in 5th position use ORDER BY id, level.

How to sum the values of column on duplicate key?

I have a table like this:
// mytable
+----+--------+-------+-------+
| id | name | key | value |
+----+--------+-------+-------+
| 1 | jack | 1 | 10 |
| 2 | peter | 1 | 5 |
| 3 | jack | 2 | 5 |
| 4 | ali | 1 | 2 |
| 5 | jack | 1 | 5 |
| 6 | jack | 1 | 10 |
| 7 | bert | 4 | 2 |
| 8 | peter | 2 | 10 |
| 9 | bert | 4 | 5 |
+----+--------+-------+-------+
Now I want to sum the numbers of value where both name and key are identical. So, I want this output:
// mynewtable
+----+--------+-------+-------+
| id | name | key | value |
+----+--------+-------+-------+
| 1 | jack | 1 | 25 |
| 2 | peter | 1 | 5 |
| 3 | jack | 2 | 5 |
| 4 | ali | 1 | 2 |
| 7 | bert | 4 | 7 |
| 8 | peter | 2 | 10 |
+----+--------+-------+-------+
Is it possible to I do that?
Edit: How can I do that for insert?
// mytable
+----+--------+-------+-------+
| id | name | key | value |
+----+--------+-------+-------+
| 1 | jack | 1 | 25 |
| 2 | peter | 1 | 5 |
| 3 | jack | 2 | 5 |
| 4 | ali | 1 | 2 |
| 7 | bert | 4 | 7 |
| 8 | peter | 2 | 10 |
+----+--------+-------+-------+
Inserting these rows:
+----+--------+-------+-------+
| 10 | jack | 1 | 5 |
+----+--------+-------+-------+
+----+--------+-------+-------+
| 11 | bert | 1 | 2 |
+----+--------+-------+-------+
What I want: (output)
// mynewtable
+----+--------+-------+-------+
| id | name | key | value |
+----+--------+-------+-------+
| 1 | jack | 1 | 30 |
| 2 | peter | 1 | 5 |
| 3 | jack | 2 | 5 |
| 4 | ali | 1 | 2 |
| 7 | bert | 4 | 7 |
| 8 | peter | 2 | 10 |
| 11 | bert | 1 | 2 |
+----+--------+-------+-------+
You have to group by more columns.
select name, key, sum(value) from mytable group by name, key;
Group by name, key
select name, key, sum(value) as value
from mytable group by name,key
check this
CREATE TABLE #testing_123
([id] int, [name] varchar(5), [key] int, [value] int)
;
INSERT INTO #testing_123
([id], [name], [key], [value])
VALUES
(1, 'jack', 1, 10),
(2, 'peter', 1, 5),
(3, 'jack', 2, 5),
(4, 'ali', 1, 2),
(5, 'jack', 1, 5),
(6, 'jack', 1, 10),
(7, 'bert', 4, 2),
(8, 'peter', 2, 10),
(9, 'bert', 4, 5)
;
query used was
select min(id) id ,name,[key],sum(value) value from #testing_123 group by name,[key] order by 1
output after insert
For the first part (to get the id column in the way requested), you could work along:
INSERT INTO mynewtable
(id, name, `key`, `value`)
SELECT
MIN(id), name, `key`, SUM(`value`)
FROM mytable
GROUP BY name, `key`
;
Now, provided mynewtable is defined with a unique index on name and key like
CREATE TABLE mynewtable
(id INT, name VARCHAR(5), `key` INT, `value` INT, UNIQUE (name, `key`));
you'd get the requested result with
INSERT INTO mynewtable
(id, name, `key`, `value`)
VALUES
(10, 'jack', 1, 5),
(11, 'bert', 1, 2)
ON DUPLICATE KEY UPDATE `value` = `value` + VALUES(`value`)
;
Beware:
It requires the unique index on name and key to work.
It might not work correctly, if there are other unique indexes and/or a primary key on the same table as well.
NB:
Please try to avoid the use of reserved words such as value and key for, e.g., column names.

Remaping numbers in table all at once

I was converting a database structure to a different one. There's this problem with ID's. The items used to reference to each other with ID - but these ID's must change because the new structure is different.
So you have a table (this is an example):
| id | ref |
+----+-----+
| 1 | 3 |
| 2 | 1 |
| 3 | 1 |
| 4 | 2 |
Now let's say that in new table, the refference id's must change like this:
| old | new |
+-----+-----+
| 1 | 2 |
| 2 | 1 |
| 3 | 4 |
| 4 | 3 |
See what happens if you subsequently UPDATE to replace old ref with new ones:
Replacing: 1=>2 Replacing: 2=>1 This is what we need at the end:
well, damn
| id | ref | | id | ref | | id | ref |
+----+-----+ +----+-----+ +----+-----+
| 1 | 3 | | 1 | 3 | | 1 | 4 |
| 2 | *2* | | 2 | 2 | | 2 | 2 |
| 3 | *2* | | 3 | 2 | | 2 | 2 |
| 4 | 2 | | 4 | *2* | | 2 | 1 |
So I need to replace it at one time. How can I do this?
Since the criteria don't matter, this will do the trick. The core of the solution is: update all rows in one go.
update YourTable
set ref =
case ref
when 1 then 2
when 2 then 1
when 3 then 4
when 4 then 3
end
If that is not possible:
add a new column 'newref'
update 'newref' in any way you want to contain the new ids
update the 'ref' column with the values from 'newref'
drop the 'newref'
This update all in one instruction
UPDATE t1 a
INNER JOIN t2 b
ON a.ref=b.old
SET a.ref=b.new;
Result
select * from t1
id ref
1 4
2 2
3 2
4 1
http://sqlfiddle.com/#!2/ab49c/1
Schema and data sample
create table t1 (id int, ref int);
create table t2 (old int, new int);
insert t1 values(1,3);
insert t1 values(2,1);
insert t1 values(3,1);
insert t1 values(4,2);
insert t2 values(1,2);
insert t2 values(2,1);
insert t2 values(3,4);
insert t2 values(4,3);

SQL, difficult fetching data query

Suppose I have such a table:
+-----+---------+-------+
| ID | TIME | DAY |
+-----+---------+-------+
| 1 | 1 | 1 |
| 2 | 2 | 1 |
| 3 | 3 | 1 |
| 1 | 1 | 2 |
| 2 | 2 | 2 |
| 3 | 3 | 2 |
| 1 | 1 | 3 |
| 2 | 2 | 3 |
| 3 | 3 | 3 |
| 1 | 1 | 4 |
| 2 | 2 | 4 |
| 3 | 3 | 4 |
| 1 | 1 | 5 |
| 2 | 2 | 5 |
| 3 | 3 | 5 |
+-----+---------+-------+
I want to fetch a table which represents 2 IDs which got the largest sum of TIME within the last 3 days (means from 3 to 5 in a DAY column)
So the correct result would be:
+-----+---------+
| ID | SUM |
+-----+---------+
| 3 | 9 |
| 2 | 6 |
+-----+---------+
The original table is much larger and more complex. So i need a generic approach.
Thanks in advance.
And so I just learned that MySQL used LIMIT instead of TOP...
fiddle
CREATE TABLE tbl (ID INT,tm INT,dy INT);
INSERT INTO tbl (id, tm, dy) VALUES
(1,1,1)
,(2,2,1)
,(3,3,1)
,(1,1,2)
,(1,1,1)
SELECT ID
,SUM(SumTimeForDay) SumTimeFromLastThreeDays
FROM (SELECT ID
,SUM(tm) SumTimeForDay
FROM tbl
GROUP BY ID, dy
HAVING dy > MAX(dy) -3) a
GROUP BY id
ORDER BY SUM(SumTimeForDay) DESC
LIMIT 2
select t1.`id`, sum(t1.`time`) as `sum`
from `table` t1
inner join ( select distinct `day` from `table` order by `day` desc limit 3 ) t2
on t2.`da`y = t1.`day`
group by t1.`id`
order by sum(t1.`time`) desc
limit 2

Extend Mysql table for same id

My table structure is:
id | type | attribute | customer_id | value
1 | 2 | 1 | 1 | some
2 | 2 | 2 | 1 | this
3 | 2 | 3 | 1 | that
4 | 2 | 1 | 2 | cool
5 | 2 | 2 | 2 | just
etc
I want to add value='mine' as attribute 4 to each customer_id.
INSERT INTO mytable
SET type='2', attribute='4, value='mine'
The question is how to bind it on customer_id and only once per customer?
INSERT INTO myTable(type, attribute, customer_id, value)
SELECT 2 type,
4 attribute,
s.customer_id,
'mine' `value`
FROM (SELECT DISTINCT customer_id FROM myTable) s