Зачем использовать ORDER с пунктом Update?
Вы можете использовать значение ORDER BY во время обновления. Предложения ORDER BY, безусловно, имеет смысл во время SELECT. Но, зачем нам нужен ORDER BY во время обновления.
Скажем, у вас есть уникальный идентификатор и поле идентификатор сотрудника таблицы.
Когда вы выполните следующую команду, чтобы увеличить идентификатор сотрудника на 100, вы можете получить сообщение об ошибке дубликатом.
mysql> UPDATE contractor set id=id+100; ERROR 1062 (23000): Duplicate entry '200' for key 'PRIMARY'
Это происходит потому, что, когда он пытается обновить значение идентификатора от 100 до 200, то уже есть существующая запись с идентификатором, как 200. Поле ID также имеет уникальный UNIQUE, в данном случае это является PRIMARY ключом. Таким образом, мы получаем вышеуказанную ошибку.
Для этого мы должны выполнить следующую команду с ORDER BY с идентификатором Desc.
mysql> UPDATE worker SET id=id+100 order by id desc; Query OK, 6 rows affected (0.01 sec) Rows matched: 7 Changed: 7 Warnings: 0
В приведенном выше случае, сначала начните с максимального идентификатора сотрудника, обновлять эту запись, а затем переходить к следующему. Таким образом, он никогда не будет иметь сценарий повторяющегося значения в процессе обновления.
Руководство по MySQL
544 страницы · 2016 · 4.78 MB · русский
by Тахагхогхи С. & Вильямс Хью Е.
MySQL по максимуму
866 страниц · 2018 · 102.51 MB · русский
by Бэрон Шварц & Петр Зайцев & Вадим Ткаченко
на главную сниппетов
2013-2021 «OIS» aka Coder
SQL SELECT TOP
Инструкция SELECT TOP используется для указания количества возвращаемых записей.
Инструкция SELECT TOP полезно для больших таблиц с тысячами записей. Возврат большого количества записей может повлиять на производительность.
Примечание: Не все базы данных поддерживают SELECT TOP.
MySQL поддерживает предложение LIMIT для выбора ограниченного числа записей, в то время как Oracle использует ROWNUM.
Синтаксис SQL Server / MS Access:
SELECT TOP number|percent column_name(s)
FROM table_nameWHERE condition;
Синтаксис MySQL:
SELECT column_name(s)
FROM table_nameWHERE condition
LIMIT number;
Синтаксис Oracle:
SELECT column_name(s)
FROM table_name
WHERE ROWNUM <= number;
Случай объединения или IF с Update
Вы также можете использовать условные обновления MySQL с помощью условных команд, как CASE, IF и т.д. Это полезно для упрощения обновления.
Вместо того чтобы использовать несколько обновлений, вы можете просто обойтись с помощью одной команды UPDATE, которая сочетает в себе все ваши операции.
Например, скажем, у нас есть следующие три оператора обновления, которые обновляют поле заработной платы на основе значения из поля отдела.
UPDATE worker SET salary = salary+1000 WHERE dept = 'Sales'; UPDATE worker SET salary = salary+500 WHERE dept = 'IT '; UPDATE worker SET salary = salary+800 WHERE dept = 'Marketing';
Вы можете объединить все перечисленные выше заявления трех UPDATE в одном заявлении UPDATE используя условие CASE, как показано ниже.
UPDATE worker SET salary = CASE dept WHEN 'Sales' THEN salary+1000 WHEN 'IT ' THEN salary+500 WHEN 'Marketing' THEN salary+500 ELSE salary END;
Так же, как CASE, вы можете также использовать IF условие для обновления значения столбца соответственно.
SQL References
SQL Keywords
ADD
ADD CONSTRAINT
ALTER
ALTER COLUMN
ALTER TABLE
ALL
AND
ANY
AS
ASC
BACKUP DATABASE
BETWEEN
CASE
CHECK
COLUMN
CONSTRAINT
CREATE
CREATE DATABASE
CREATE INDEX
CREATE OR REPLACE VIEW
CREATE TABLE
CREATE PROCEDURE
CREATE UNIQUE INDEX
CREATE VIEW
DATABASE
DEFAULT
DELETE
DESC
DISTINCT
DROP
DROP COLUMN
DROP CONSTRAINT
DROP DATABASE
DROP DEFAULT
DROP INDEX
DROP TABLE
DROP VIEW
EXEC
EXISTS
FOREIGN KEY
FROM
FULL OUTER JOIN
GROUP BY
HAVING
IN
INDEX
INNER JOIN
INSERT INTO
INSERT INTO SELECT
IS NULL
IS NOT NULL
JOIN
LEFT JOIN
LIKE
LIMIT
NOT
NOT NULL
OR
ORDER BY
OUTER JOIN
PRIMARY KEY
PROCEDURE
RIGHT JOIN
ROWNUM
SELECT
SELECT DISTINCT
SELECT INTO
SELECT TOP
SET
TABLE
TOP
TRUNCATE TABLE
UNION
UNION ALL
UNIQUE
UPDATE
VALUES
VIEW
WHERE
MySQL Functions
String Functions:
ASCII
CHAR_LENGTH
CHARACTER_LENGTH
CONCAT
CONCAT_WS
FIELD
FIND_IN_SET
FORMAT
INSERT
INSTR
LCASE
LEFT
LENGTH
LOCATE
LOWER
LPAD
LTRIM
MID
POSITION
REPEAT
REPLACE
REVERSE
RIGHT
RPAD
RTRIM
SPACE
STRCMP
SUBSTR
SUBSTRING
SUBSTRING_INDEX
TRIM
UCASE
UPPER
Numeric Functions:
ABS
ACOS
ASIN
ATAN
ATAN2
AVG
CEIL
CEILING
COS
COT
COUNT
DEGREES
DIV
EXP
FLOOR
GREATEST
LEAST
LN
LOG
LOG10
LOG2
MAX
MIN
MOD
PI
POW
POWER
RADIANS
RAND
ROUND
SIGN
SIN
SQRT
SUM
TAN
TRUNCATE
Date Functions:
ADDDATE
ADDTIME
CURDATE
CURRENT_DATE
CURRENT_TIME
CURRENT_TIMESTAMP
CURTIME
DATE
DATEDIFF
DATE_ADD
DATE_FORMAT
DATE_SUB
DAY
DAYNAME
DAYOFMONTH
DAYOFWEEK
DAYOFYEAR
EXTRACT
FROM_DAYS
HOUR
LAST_DAY
LOCALTIME
LOCALTIMESTAMP
MAKEDATE
MAKETIME
MICROSECOND
MINUTE
MONTH
MONTHNAME
NOW
PERIOD_ADD
PERIOD_DIFF
QUARTER
SECOND
SEC_TO_TIME
STR_TO_DATE
SUBDATE
SUBTIME
SYSDATE
TIME
TIME_FORMAT
TIME_TO_SEC
TIMEDIFF
TIMESTAMP
TO_DAYS
WEEK
WEEKDAY
WEEKOFYEAR
YEAR
YEARWEEK
Advanced Functions:
BIN
BINARY
CASE
CAST
COALESCE
CONNECTION_ID
CONV
CONVERT
CURRENT_USER
DATABASE
IF
IFNULL
ISNULL
LAST_INSERT_ID
NULLIF
SESSION_USER
SYSTEM_USER
USER
VERSION
SQL Server Functions
String Functions:
ASCII
CHAR
CHARINDEX
CONCAT
Concat with +
CONCAT_WS
DATALENGTH
DIFFERENCE
FORMAT
LEFT
LEN
LOWER
LTRIM
NCHAR
PATINDEX
QUOTENAME
REPLACE
REPLICATE
REVERSE
RIGHT
RTRIM
SOUNDEX
SPACE
STR
STUFF
SUBSTRING
TRANSLATE
TRIM
UNICODE
UPPER
Numeric Functions:
ABS
ACOS
ASIN
ATAN
ATN2
AVG
CEILING
COUNT
COS
COT
DEGREES
EXP
FLOOR
LOG
LOG10
MAX
MIN
PI
POWER
RADIANS
RAND
ROUND
SIGN
SIN
SQRT
SQUARE
SUM
TAN
Date Functions:
CURRENT_TIMESTAMP
DATEADD
DATEDIFF
DATEFROMPARTS
DATENAME
DATEPART
DAY
GETDATE
GETUTCDATE
ISDATE
MONTH
SYSDATETIME
YEAR
Advanced Functions
CAST
COALESCE
CONVERT
CURRENT_USER
IIF
ISNULL
ISNUMERIC
NULLIF
SESSION_USER
SESSIONPROPERTY
SYSTEM_USER
USER_NAME
MS Access Functions
String Functions:
Asc
Chr
Concat with &
CurDir
Format
InStr
InstrRev
LCase
Left
Len
LTrim
Mid
Replace
Right
RTrim
Space
Split
Str
StrComp
StrConv
StrReverse
Trim
UCase
Numeric Functions:
Abs
Atn
Avg
Cos
Count
Exp
Fix
Format
Int
Max
Min
Randomize
Rnd
Round
Sgn
Sqr
Sum
Val
Date Functions:
Date
DateAdd
DateDiff
DatePart
DateSerial
DateValue
Day
Format
Hour
Minute
Month
MonthName
Now
Second
Time
TimeSerial
TimeValue
Weekday
WeekdayName
Year
Other Functions:
CurrentUser
Environ
IsDate
IsNull
IsNumeric
SQL Quick Ref
оконные функции
Начиная с MariaDB 10.2 / MySQL 8 добавлена поддержка оконных функций. С помощью row_number() можно для каждого пользователя сделать отдельную нумерацию сообщений в порядке убывания даты. После чего выбрать те записи, у которых № меньше или равен 3.
select post_id, user_id, date_added, post_text from (select posts.*,
row_number() over (partition by user_id order by date_added desc) ifrom posts) t where i <= 3;
Производительность — двойное сканирование таблицы: сначала для нумерации (нет возможности ограничиться нумерацией только нескольких строк из группы), потом отбросить не удовлетворяющие условию where i <= 3.
Для случайных сообщений пользователя достаточно заменить сортировку по убыванию даты order by date_added desc на случайную — order by rand().
Шаг 2: Выберите свой входной файл (XLSX) и проверьте данные
Если вы уже запускали этот мастер раньше, вы можете выбрать файлы из предыдущих сеансов.
Когда вы выберете файл, мы захватим первые 100 строк для просмотра ниже. Этот «Предел строк предварительного просмотра» определяет, сколько строк вы можете использовать для проверки ИМПОРТА по мере прохождения мастера. Вы можете увеличить его, но это потребует больше ресурсов, так что не сходите с ума.
Кроме того, есть ли в вашем файле Excel заголовки столбцов? Хотим ли мы рассматривать их как строку к таблице? Скорее всего, нет. Если вы снимите флажок «Заголовок», имена столбцов станут новой строкой в вашей таблице – и, вероятно, не будут вставлены.
Иногда ваш файл Excel имеет несколько заголовков, или вам может потребоваться импортировать только определенное подмножество электронной таблицы. Используйте опцию «Пропустить строки», чтобы получить правильные данные.
пользовательские переменные
Та же идея, что и в предыдущем варианте, только реализована с помощью пользовательских переменных (user variables). Актуально для версий, в которых нет оконных функций.
select post_id, user_id, date_added, post_text from(select posts.*, if(@gr=user_id, @i:=@i+1, @i:=1 + least(@gr:=user_id,)) xfrom posts, (select @i:=, @gr:=) t order by user_id, date_added desc) t1 where x <=3;
Как и в примере с row_number(), мы нумеруем сообщения каждого пользователя в порядке убывания даты добавления (только делаем это с помощью пользовательских переменных), затем оставляем только те строки, у которых № меньше или равен 3.
Способ можно применять и для выборки нескольких случайных сообщений юзера. Однако простая замена сортировки по убыванию даты на случайную не даст нужного эффекта.
select post_id, user_id, date_added, post_text from(select t2.*, if(@gr=user_id, @i:=@i+1, @i:=1 + least(@gr:=user_id,)) xfrom (select posts.*, rand() q, @z:=1 from posts) t2, (select @i:=, @gr:=) t order by user_id, q) t1 where x <=3
Обратите внимание на добавление ещё одной переменной @z:=1, которая более нигде не применяется. С некоторых пор оптимизатор научился упрощать тривиальные с его точки зрения from-подзапросы, перенося условия из них во внешний запрос
Однако, если в подзапросе используются переменные, то пока оптимизатор материализует такие подзапросы.
В общем, пользовательские переменные — мощный инструмент написания и оптимизации запросов, но нужно быть очень внимательными при работе с ними, понимать на каком эффекте основан, используемый вами трюк, и проверять работоспособность в новых версиях. Подробнее см Оптимизация запросов MySQL с использованием пользовательских переменных
Множественное обновление таблиц (с помощью Left Join)
Аналогично предыдущему примеру внутреннего соединения, мы можем также использовать левое соединение.
Когда мы используем внутреннее соединение, мы не указываем ключевое слово “inner join”, так как это по умолчанию при объединении нескольких таблиц.
Однако при использовании соединения слева мы должны явно указать “left join”, как показано ниже.
mysql> UPDATE worker LEFT JOIN benefits on worker.dept = benefits.dept -> SET worker.salary = worker.salary+500 -> WHERE benefits.bonus is null; Query OK, 2 rows affected (0.03 sec) Rows matched: 2 Changed: 2 Warnings: 0
Вот выход после вышеуказанного обновления.
mysql> SELECT * FROM worker; +-----+--------+------------+--------+ | id | name | dept | salary | +-----+--------+------------+--------+ | 100 | Andrey | Sales | 7500 | | 200 | Anton | Sales | 7500 | | 300 | Maxim | IT | 7000 | | 400 | Dimon | IT | 5500 | | 500 | Anton | Marketing | 5800 | | 501 | Anna | Marketing | 5800 | +-----+--------+------------+--------+
Практическое упражнение №4:
На основании таблицы employees ниже, модифицируйте тип данных столбца employee_name в varchar2 (80).
Oracle PL/SQL
CREATE TABLE employees
( employee_number number(10) not null,
employee_name >varchar2(50) not null,
department_id number(10),
CONSTRAINT employees_pk PRIMARY KEY (employee_number)
);
1 |
CREATETABLEemployees employee_name>varchar2(50)notnull, department_idnumber(10), CONSTRAINTemployees_pkPRIMARYKEY(employee_number) |
Решение для практического упражнения №4:
Следующий оператор Oracle/PLSQL ALTER TABLE модифицирует тип данных для столбца employee_name в varchar2 (80):
Oracle PL/SQL
ALTER TABLE employees
MODIFY employee_name varchar2(80);
1 |
ALTERTABLEemployees MODIFYemployee_namevarchar2(80); |
UPDATE несколько записей
Именно предложение WHERE определяет, сколько записей будет обновлено.
Следующая инструкция SQL обновит имя контакта до «Juan» для всех записей, где страна — «Mexico»:
Пример
UPDATE Customers
SET ContactName=’Juan’
WHERE Country=’Mexico’;
Выбор из таблицы «Customers» теперь будет выглядеть следующим образом:
CustomerID | CustomerName | ContactName | Address | City | PostalCode | Country |
---|---|---|---|---|---|---|
1 | Alfreds Futterkiste | Alfred Schmidt | Obere Str. 57 | Frankfurt | 12209 | Germany |
2 | Ana Trujillo Emparedados y helados | Juan | Avda. de la Constitución 2222 | México D.F. | 05021 | Mexico |
3 | Antonio Moreno Taquería | Juan | Mataderos 2312 | México D.F. | 05023 | Mexico |
4 | Around the Horn | Thomas Hardy | 120 Hanover Sq. | London | WA1 1DP | UK |
5 | Berglunds snabbköp | Christina Berglund | Berguvsvägen 8 | Luleå | S-958 22 | Sweden |
Практическое упражнение №7:
На основании таблицы departments ниже, переименовать столбец department_name в dept_name.
Oracle PL/SQL
CREATE TABLE departments
( department_id number(10) not null,
department_name varchar2(50) not null,
CONSTRAINT departments_pk PRIMARY KEY (department_id)
);
1 |
CREATETABLEdepartments department_namevarchar2(50)notnull, CONSTRAINTdepartments_pkPRIMARYKEY(department_id) |
Решение для практического упражнения №7:
Следующий оператор Oracle/PLSQL ALTER TABLE переименует столбец department_name в dept_name в таблице departments:
Oracle PL/SQL
ALTER TABLE departments
RENAME COLUMN department_name to dept_name;
1 |
ALTERTABLEdepartments RENAMECOLUMNdepartment_nametodept_name; |
Узнайте как использовать оператор ALTER TABLE в распространенных БД:
- ALTER TABLE SQL Server
- ALTER TABLE MySQL
- ALTER TABLE PostgreSQL
- ALTER TABLE MariaDB
- ALTER TABLE SQLite
Ограничение колличества записей при обновлении
Мы также можем использовать опцию LIMIT, чтобы ограничить количество записей, которые должны быть обновлены.
Даже если условие, где соответствует несколько записей, оператор обновления будет обновлять только 1-е X количество записей, указанных в значении LIMIT.
В следующем примере мы присваиваем зарплату всех записей до 6500, так как мы не имеем WHERE. Но, мы используем LIMIT 3. Это означает, что она будет обновлять зарплату только первым трем записям для условия согласования.
mysql> UPDATE worker SET salary=6500 LIMIT 3; Query OK, 3 rows affected (0.01 sec) Rows matched: 3 Changed: 3 Warnings: 0
Как видно из следующего выхода, только 1-е три записи обновляются предыдущей командой.
mysql> SELECT * FROM worker; +-----+--------+-----------+--------+ | id | name | dept | salary | +-----+--------+-----------+--------+ | 100 | Andrey | Sales | 6500 | | 200 | Anton | Sales | 6500 | | 300 | Maxim | Sales | 6500 | | 400 | Dimon | Marketing | 5000 | | 500 | Anton | Marketing | 5000 | | 501 | Anna | Marketing | 5000 | +-----+--------+-----------+--------+
Одна вещь, чтобы иметь в виду, что LIMIT 3 на самом деле не означает, что обновление будет продолжать идти, пока он не обновит 3 записей. Вместо этого оператор обновления прекратит выполнение, как только он обработал первые 3 строки, которые соответствовали условию выполнения, независимо от того, были ли действительно обновлены эти записи или нет.
Вставка строк, некоторые из которых уже существуют в целевой таблице
Существование строк определяется по значению уникальных ключей. В зависимости от ситуации мы можем выбрать разные способы поведения при совпадении значений уникальных столбцов.
Игнорирование INSERT IGNORE INTO
Например если мы вставляем строку с PK = 1, и при этом в таблице уже есть PK = 1 то MySQL выдаст ошибку:
/* ERROR 1062 (23000): Duplicate entry '1' for key 'PRIMARY' */
Выполнение запроса на этом прервется, однако нам в некоторых случаях хотелось бы просто вставить данные, игнорируя ошибки. В этом нам поможет INSERT IGNORE INTO:
INSERT IGNORE INTO table1 (a, b, c) VALUES (1, 222, 333), (2, 555, 666), (3, 555, 333);
Просто добавляем IGNORE в наш запрос и ошибки будут игнорироваться
Вставка с заменой существующих значений REPLACE INTO
REPLACE работает также INSERT, но если совпадают уникальные ключи, то старая строка (или строки!) удаляется до вставки новой.
В таком случае наш пример выглядит следующим образом:
REPLACE INTO table1 (a, b, c) VALUES (1, 222, 333), (2, 555, 666), (3, 555, 333);
Обновление некоторых полей, при существовании строк ON DUPLICATE KEY UPDATE
При совпадении ключей, мы можем также заменить некоторые или все поля в строке.
Наш запрос будет выглядеть так:
INSERT INTO table1 (a,b,c) VALUES (1,2,3) ON DUPLICATE KEY UPDATE c=VALUES(c);
В данном примере если у нас какой-то уникальный ключ совпадает, то мы не производим вставку, а обновляем существующую строку или строки путем присваивания столбцу «c» значения, которое у нас перечислено в VALUES.
Иными словами, если ключ совпадает, то мы просто обновим данные столбца «с» а остальные столбцы трогать не будем.
Иногда нам нужно при совпадении ключей обновить все значения. Этом можно сделать просто перечислив все столбцы:
INSERT INTO table1 (a,b,c) VALUES (1,2,3) ON DUPLICATE KEY UPDATE a=VALUES(a), b=VALUES(b), c=VALUES(c);
При обновлении столбцов мы также можем использовать разные выражения, например:
INSERT INTO table1 (a,b,c) VALUES (1,2,3),(4,5,6) ON DUPLICATE KEY UPDATE c=VALUES(a)+VALUES(b);
Подробнее про ON DUPLICATE KEY UPDATE
MySQL error 1093
В MySQL нельзя изменять данные и одновременно делать выборку из той же таблицы в подзапросе. Запросы вида
DELETE FROM t WHERE col = (SELECT … FROM t …);UPDATE t … WHERE col = (SELECT … FROM t …);{INSERT|REPLACE} INTO t (SELECT … FROM t …);
ERROR 1093 (HY000): You can’t specify target table ‘t’ for update in FROM clause.
Есть два варианта решения проблемы:
1. Универсальный способ, рекомендуемый в документации, — использовать вложенный подзапрос.
DELETE FROM t WHERE col = (SELECT * FROM (SELECT … FROM t…) AS t1);UPDATE t … WHERE col = (SELECT * FROM (SELECT … FROM t…) AS t1);{INSERT|REPLACE} INTO t (SELECT * FROM (SELECT … FROM t…) AS t1);
В этом случае подзапрос к изменяемой таблице оказывается в части FROM и материализуется во временную таблицу в начале выполнения запроса. Т.о. при обновлении чтение данных будет идти из временной таблицы, а не из той, которая обновляется.
2. Для запросов UPDATE и DELETE можно использовать многотабличную форму. Например, для UPDATE запрос выше примет вид:
UPDATE t, (SELECT … FROM t …) t1 … WHERE t.col=t1.col;
По сути это тот же метод, что и предыдущий — подзапрос переносится в часть перечисления таблиц. Но кроме чуть более компактной записи многотабличная форма операторов UPDATE/DELETE в некоторых случаях позволяет вообще обойтись без подзапроса.
Примеры:
-
мы хотим удалить из первой таблицы строки, не имеющие соответствия (по id) во второй.
DELETE t1 FROM t1 LEFT JOIN t2 ON t1.id=t2.id WHERE t2.id IS NULL;
Для сравнения через подзапрос:DELETE FROM t1 WHERE id IN (SELECT * FROM (SELECT t1.id FROM t1 LEFT JOIN t2 ON t1.id=t2.id WHERE t2.id IS NULL) as t_x);
-
удалить из таблицы дубликаты (строки с одинаковыми значениями поля col) с меньшим id
DELETE t1 FROM t t1 JOIN t t2ON t1.col = t2.col AND t1.id < t2.id;
через подзапросDELETE t FROM t LEFT JOIN (SELECT max(id) as id, col FROM t GROUP BY col) t1 USING(id) WHERE t1.id IS NULL;
-
а вот задача пометить важными статьи авторов, имеющих более 10 публикаций, без подзапроса не решается:
UPDATE articles SET important=1 WHERE author IN (SELECT * FROM (SELECT author FROM articles GROUP BY 1 HAVING count(*)>10) t);
илиUPDATE articles, (SELECT author FROM articles GROUP BY 1 HAVING count(*)>10) t SET important=1 WHERE author = t.author;
-
в завершение рассмотрим пример, когда подзапрос находится в части SET. Например, для строк с id>10 мы хотим установить значение поля col равное значению этого поля для строки с id равным 2.
UPDATE t as t1 JOIN t as t2 ON t2.id=2 SET t1.col = t2.col WHERE t1.id > 10;
через подзапросUPDATE t
SET col = (SELECT * FROM (SELECT col FROM t WHERE id = 2) AS t1)
WHERE id = >10;
Изменение нескольких столбцов в таблице
Синтаксис
Синтаксис ALTER TABLE для редактирования нескольких столбцов в существующей таблице Oracle:
ALTER TABLE table_name
MODIFY (column_1 column_type,
column_2 column_type,
…
column_n column_type);
Пример
Рассмотрим пример, который показывает, как изменить несколько столбцов в таблице Oracle с помощью оператора ALTER TABLE.
Например:
Oracle PL/SQL
ALTER TABLE customers
MODIFY (customer_name varchar2(100) not null,
city varchar2(75));
1 |
ALTERTABLEcustomers MODIFY(customer_namevarchar2(100)notnull, cityvarchar2(75)); |
В этом примере ALTER TABLE модифицирует столбцы customer_name и city.
подзапросы lateral
В MySQL 8.0.14 добавлена поддержка зависимых подзапросов в части FROM, с помощью которых наша задача решается оптимальным образом. Сначала формируется список идентификаторов пользователей (производная таблица t1) и для каждого из выбираются нужные строки (коррелированный from-подзапрос t2).
select t2.* from (select user_id from posts group by user_id) as t1,
lateral (select * from posts where t1.user_id=posts.user_id order by date_added desc limit 3) as t2;
К удивлению, при выборе строк в подзапросе t2 сервер читает все строки группы и делает файловую сортировку вместо нахождения 3 нужных строк по уникальному индексу (user_id, date_added). Возможно в будущих версиях это поведение будет исправлено.
На сегодняшний день можно применить следующий трюк, благодаря которому MySQL будет использовать индекс — расширить выражение сортировки следующим образом:
.. order by user_id desc, date_added desc limit 3
Для выборки случайных строк из группы достаточно в lateral подзапросе заменить сортировку на случайную — order by rand().
Обновление значения столбца с выражением
При присвоении значения в столбце после SET, вы не всегда должны указывать статические значения. Вы также можете использовать выражения, как показано ниже.
Ниже приводится очень простое выражение, где оно увеличивает значение заработной платы на 500 для всех сотрудников отдела IT.
mysql> UPDATE worker SET salary=salary+500 WHERE dept='IT'; Query OK, 3 rows affected (0.01 sec) Rows matched: 4 Changed: 3 Warnings: 0
Были только 4 записи, которые соответствовали условию выше. Но только три записи были обновлены, как показано ниже, в качестве одного из записей сотрудников, который принадлежит к техническому отделу, имел нулевое значение в поле заработной платы. Таким образом, зарплата выше + 500 выражение по прежнему NULL, и не обновляется эта конкретную запись.
mysql> SELECT * FROM worker; +-----+--------+------------+--------+ | id | name | dept | salary | +-----+--------+------------+--------+ | 100 | Andrey | IT | 5500 | | 200 | Anton | IT | 6000 | | 300 | Maxim | Marketing | 7000 | | 400 | Dimon | Marketing | 9500 | | 500 | Anton | IT | 6500 | | 501 | Anna | IT | NULL | +-----+--------+------------+--------+
Обновление только выбранных строк
Вместо того, чтобы обновить все записи, вы можете выборочно обновить определенные записи на основе условия WHERE.
В следующем примере будет обновлять таблицу сотрудников и назначить сотрудника, который имеют зарплату больше или равно 7000 для отдела маркетинга.
mysql> UPDATE worker SET dept='Marketing' WHERE salary >=7000; Query OK, 2 rows affected (0.01 sec) Rows matched: 2 Changed: 2 Warnings: 0
Были только две записи, которые соответствовали выше, таблица обновилась, как показано ниже.
mysql> SELECT * FROM worker; +-----+--------+------------+--------+ | id | name | dept | salary | +-----+--------+------------+--------+ | 100 | Andrey | IT | 5000 | | 200 | Anton | IT | 5500 | | 300 | Maxim | Marketing | 7000 | | 400 | Dimon | Marketing | 9500 | | 500 | Anton | IT | 6000 | | 501 | Anna | IT | NULL | +-----+--------+------------+--------+
Мы обсуждали много различных практических условий WHERE в нашем учебнике MySQL по команде SELECT. Это очень полезно, чтобы понять, как использовать предложение WHERE эффективно во время UPDATE: 25 основных примеров в MySQL для команды SELECT.
Пример использования условия EXISTS
Вы также можете выполнять более сложные обновления в Oracle.
Вы можете обновлять записи в одной таблице на основе значений другой таблицы. Поскольку вы не можете перечислить более одной таблицы в операторе Oracle UPDATE, то вы можете использовать Oracle условие EXISTS.
Например:
Oracle PL/SQL
UPDATE suppliers
SET supplier_name = (SELECT customers.customer_name
FROM customers
WHERE customers.customer_id = suppliers.supplier_id)
WHERE EXISTS (SELECT customers.customer_name
FROM customers
WHERE customers.customer_id = suppliers.supplier_id);
1 |
UPDATEsuppliers SETsupplier_name=(SELECTcustomers.customer_name FROMcustomers WHEREcustomers.customer_id=suppliers.supplier_id) WHEREEXISTS(SELECTcustomers.customer_name FROMcustomers WHEREcustomers.customer_id=suppliers.supplier_id); |
В этом Oracle примере UPDATE, всякий раз, когда supplier_id соответствует значение customer_id, то supplier_name будет перезаписано в customer_name из таблицы customers.
Вывод данных из нескольких таблиц
Если у вас есть несколько связанных таблиц, то с помощью вы можете выводить их данные составляя из них одну таблицу.
Например мы имеем таблицу с книгами — books и их заказами — orders.
Выведем колонки id, book_id и status для таблицы orders.
Имея идентификаторы записей таблицы books в колонке book_id, мы можем соотнести их с колонкой id в таблице books с помощью команды . В результате мы можем узнать статус заказа для каждой книги.
Выведем колонки title, author, price из таблицы books и колонку status из таблицы orders.
Вывести колонки с одинаковыми именами, например id, в данном случае не получится, т.к. они имеются в обоих таблицах.