значение столбца подкачки, если столбец a ниже столбца b [дубликат]

Ответ - каждое ключевое слово по поиску

Items.find({"description": {
                        '$regex': new RegExp(variable, "i")
                    }}).fetch();
104
задан Liedman 1 September 2008 в 10:54
поделиться

17 ответов

Мне просто приходилось иметь дело с тем же, и я обобщу свои выводы.

  1. Подход UPDATE table SET X=Y, Y=X, очевидно, не работает, поскольку он просто установит оба значения в Y .
  2. Вот метод, который использует временную переменную. Спасибо Антонию из комментариев http://beerpla.net/2009/02/17/swapping-column-values-in-mysql/ для настройки «IS NOT NULL». Без него запрос работает непредсказуемо. См. Схему таблицы в конце сообщения. Этот метод не меняет значения, если один из них равен NULL. Используйте метод №3, который не имеет этого ограничения. UPDATE swap_test SET x=y, y=@temp WHERE (@temp:=x) IS NOT NULL;
  3. Этот метод был предложен Dipin in, но опять же комментарии http://beerpla.net/2009/02/17/swapping-column-values-in-mysql / . Я думаю, что это самое элегантное и чистое решение. Он работает как с значениями NULL, так и с не-NULL. UPDATE swap_test SET x=(@temp:=x), x = y, y = @temp;
  4. Другой подход, с которым я столкнулся, кажется, работает: UPDATE swap_test s1, swap_test s2 SET s1.x=s1.y, s1.y=s2.x WHERE s1.id=s2.id;

По существу, первая таблица обновляется, а вторая - используется для извлечения старых данных. Обратите внимание, что для этого подхода необходим первичный ключ.

Это моя тестовая схема:

CREATE TABLE `swap_test` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `x` varchar(255) DEFAULT NULL,
  `y` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB;

INSERT INTO `swap_test` VALUES ('1', 'a', '10');
INSERT INTO `swap_test` VALUES ('2', NULL, '20');
INSERT INTO `swap_test` VALUES ('3', 'c', NULL);
149
ответ дан Paul Dixon 18 August 2018 в 07:05
поделиться
  • 1
    Как отмечено в документах MySQL, нецелесообразно назначать и читать переменные в одном выражении. Порядок операций не гарантируется. Таким образом, единственным безопасным способом является # 4 – AMIB 27 January 2013 в 12:01
  • 2
    Вариант 4 работал для меня. Очевидно, вы можете добавить дополнительные условия в предложение where, если вам нужно поменять местами столбцы только на несколько строк. – Brad Campbell 1 March 2013 в 20:51
  • 3
    Вы знаете, я никогда не думал, что будет практическое использование для этого глупого вопроса интервью с просьбой обменять две переменные без использования временного, но вот оно, и для целых чисел это действительно будет работать: update swap_test set x = x + y, у = х, х = х; – izak 15 September 2014 в 14:15
  • 4
    Большая часть этого ответа - прямая копия / вставка из beerpla.net/2009/02/17/swapping-column-values-in-mysql – Lady Bird 25 May 2015 в 16:18
  • 5
    @Jhawins Это потому, что beerpla.net - это мой блог. – Artem Russakovskii 26 May 2015 в 21:26

Предполагая, что вы подписали целые числа в своих столбцах, вам может потребоваться использовать CAST (a ^ b AS SIGNED), так как результатом оператора ^ является неподписанное 64-битное целое число в MySQL.

В случае, если это кому-то поможет, вот метод, который я использовал для обмена одним и тем же столбцом между двумя заданными строками:

SELECT BIT_XOR(foo) FROM table WHERE key = $1 OR key = $2

UPDATE table SET foo = CAST(foo ^ $3 AS SIGNED) WHERE key = $1 OR key = $2

, где $ 1 и $ 2 являются ключами двух строк, а $ 3 - результатом первого запроса .

1
ответ дан Artelius 18 August 2018 в 07:05
поделиться

Следующий код работает для всех сценариев моего быстрого тестирования:

UPDATE table swap_test
   SET x=(@temp:=x), x = y, y = @temp
19
ответ дан Dave Jarvis 18 August 2018 в 07:05
поделиться

[f1] Что-то вроде этого?

Изменить: О комментарии Грега: Нет, это не работает:

[f2]

4
ответ дан fijter 18 August 2018 в 07:05
поделиться
  • 1
    Только для записи: этот работает в PostgreSQL, в то время как not работает в MySQL. – str 19 October 2011 в 23:05

Я считаю, что промежуточная переменная обмена является лучшей практикой таким образом:

update z set c1 = @c := c1, c1 = c2, c2 = @c

Во-первых, она работает всегда; во-вторых, он работает независимо от типа данных.

Несмотря на Both

update z set c1 = c1 ^ c2, c2 = c1 ^ c2, c1 = c1 ^ c2

и

update z set c1 = c1 + c2, c2 = c1 - c2, c1 = c1 - c2

, работают обычно, только для типа данных данных путь, и вы несете ответственность за предотвращение переполнения, вы не можете использовать XOR между подписанным и unsigned, вы также не можете использовать сумму для возможности переполнения.

И

update z set c1 = c2, c2 = @c where @c := c1

не работает, если c1 имеет значение 0 или NULL или нулевую длину или просто пробелы.

Нам нужно изменить его на

update z set c1 = c2, c2 = @c where if((@c := c1), true, true)

Вот скрипты:

mysql> create table z (c1 int, c2 int)
    -> ;
Query OK, 0 rows affected (0.02 sec)

mysql> insert into z values(0, 1), (-1, 1), (pow(2, 31) - 1, pow(2, 31) - 2)
    -> ;
Query OK, 3 rows affected (0.00 sec)
Records: 3  Duplicates: 0  Warnings: 0

mysql> select * from z;
+------------+------------+
| c1         | c2         |
+------------+------------+
|          0 |          1 |
|         -1 |          1 |
| 2147483647 | 2147483646 |
+------------+------------+
3 rows in set (0.02 sec)

mysql> update z set c1 = c1 ^ c2, c2 = c1 ^ c2, c1 = c1 ^ c2;
ERROR 1264 (22003): Out of range value for column 'c1' at row 2
mysql> update z set c1 = c1 + c2, c2 = c1 - c2, c1 = c1 - c2;
ERROR 1264 (22003): Out of range value for column 'c1' at row 3

mysql> select * from z;
+------------+------------+
| c1         | c2         |
+------------+------------+
|          0 |          1 |
|          1 |         -1 |
| 2147483646 | 2147483647 |
+------------+------------+
3 rows in set (0.02 sec)

mysql> update z set c1 = c2, c2 = @c where @c := c1;
Query OK, 2 rows affected (0.00 sec)
Rows matched: 2  Changed: 2  Warnings: 0

mysql> select * from z;
+------------+------------+
| c1         | c2         |
+------------+------------+
|          0 |          1 |
|         -1 |          1 |
| 2147483647 | 2147483646 |
+------------+------------+
3 rows in set (0.00 sec)

mysql> select * from z;
+------------+------------+
| c1         | c2         |
+------------+------------+
|          1 |          0 |
|          1 |         -1 |
| 2147483646 | 2147483647 |
+------------+------------+
3 rows in set (0.00 sec)

mysql> update z set c1 = @c := c1, c1 = c2, c2 = @c;
Query OK, 3 rows affected (0.02 sec)
Rows matched: 3  Changed: 3  Warnings: 0

mysql> select * from z;
+------------+------------+
| c1         | c2         |
+------------+------------+
|          0 |          1 |
|         -1 |          1 |
| 2147483647 | 2147483646 |
+------------+------------+
3 rows in set (0.00 sec)

mysql>update z set c1 = c2, c2 = @c where if((@c := c1), true, true);
Query OK, 3 rows affected (0.02 sec)
Rows matched: 3  Changed: 3  Warnings: 0

mysql> select * from z;
+------------+------------+
| c1         | c2         |
+------------+------------+
|          1 |          0 |
|          1 |         -1 |
| 2147483646 | 2147483647 |
+------------+------------+
3 rows in set (0.00 sec)
4
ответ дан hylepo 18 August 2018 в 07:05
поделиться
  • 1
    +1 для окончательного поиска хорошего использования для глупого вопроса интервью, где вам нужно поменять две переменные без временной ;-) – izak 15 September 2014 в 14:16

Таблица UPDATE SET X = Y, Y = X сделает то, что вы хотите (отредактируйте: в PostgreSQL, а не в MySQL, см. ниже). Значения берутся из старой строки и присваиваются новой копии той же строки, затем старая строка заменяется. Вам не нужно прибегать к использованию временной таблицы, временного столбца или других трюков подкачки.

@ D4V360: Я вижу. Это шокирует и неожиданно. Я использую PostgreSQL, и мой ответ работает правильно (я попробовал). См. Документы PostgreSQL UPDATE (в разделе «Параметры, выражение»), где упоминается, что выражения в правой части предложений SET явно используют старые значения столбцов. Я вижу, что соответствующие MySQL UPDATE docs содержат инструкцию «Назначения UPDATE с одной таблицей обычно оцениваются слева направо», что подразумевает поведение, которое вы описываете.

Полезно знать.

8
ответ дан joshuahedlund 18 August 2018 в 07:05
поделиться
  • 1
    Спасибо Greg и D4V360, приятно знать различия в PostgreSQL и MySQL о поведении запросов обновления. – Vijay Dev 25 October 2008 в 17:41
  • 2
    & Quot; x = y, y = x & quot; подход также работает в Oracle, для чего он стоит. – Burhan Ali 17 October 2012 в 17:52
  • 3
    Я использовал PostgreSQL и SET X = Y, Y = X спас меня :) – Anonymous 28 June 2013 в 11:00
  • 4
    ИМХО этот ответ беспорядок - плохой совет с "oops never mind & quot; прилагается. Половина из них должна быть комментарием, и единственной частью остатка, которая имеет отношение к вопросу, является ссылка на документы MySQL ... – Air 28 January 2014 в 00:57

Я не пробовал, но

UPDATE tbl SET @temp=X, X=Y, Y=@temp

Могу сделать это.

Mark

1
ответ дан MarkR 18 August 2018 в 07:05
поделиться

Хорошо, так просто для удовольствия, вы могли бы это сделать! (предполагая, что вы меняете строковые значения).

mysql> select * from swapper;
+------+------+
| foo  | bar  |
+------+------+
| 6    | 1    | 
| 5    | 2    | 
| 4    | 3    | 
+------+------+
3 rows in set (0.00 sec)

mysql> update swapper set 
    -> foo = concat(foo, "###", bar),
    -> bar = replace(foo, concat("###", bar), ""),
    -> foo = replace(foo, concat(bar, "###"), "");

Query OK, 3 rows affected (0.00 sec)
Rows matched: 3  Changed: 3  Warnings: 0

mysql> select * from swapper;
+------+------+
| foo  | bar  |
+------+------+
| 1    | 6    | 
| 2    | 5    | 
| 3    | 4    | 
+------+------+
3 rows in set (0.00 sec)

Хорошая забава злоупотребляет процессом оценки слева направо в MySQL.

Кроме того, просто используйте XOR, если они числа. Вы упомянули координаты, так что у вас есть прекрасные целочисленные значения или сложные строки?

Изменить: материал XOR работает, как это, кстати:

update swapper set foo = foo ^ bar, bar = foo ^ bar, foo = foo ^ bar;
5
ответ дан mercutio 18 August 2018 в 07:05
поделиться

Это, безусловно, работает! Я просто нуждался в нем, чтобы обменять цены на Евро и SKK. :)

UPDATE tbl SET X=Y, Y=@temp where @temp:=X;

Вышеуказанное не будет работать (ERROR 1064 (42000): у вас есть ошибка в синтаксисе SQL)

2
ответ дан nawfal 18 August 2018 в 07:05
поделиться
CREATE TABLE Names
(
F_NAME VARCHAR(22),
L_NAME VARCHAR(22)
);

INSERT INTO Names VALUES('Ashutosh', 'Singh'),('Anshuman','Singh'),('Manu', 'Singh');

UPDATE Names N1 , Names N2 SET N1.F_NAME = N2.L_NAME , N1.L_NAME = N2.F_NAME 
WHERE N1.F_NAME = N2.F_NAME;

SELECT * FROM Names;
0
ответ дан Pang 18 August 2018 в 07:05
поделиться

Вы можете взять сумму и вычесть противоположное значение с помощью X и Y

UPDATE swaptest SET X=X+Y,Y=X-Y,X=X-Y;

Вот пример теста (и он работает с отрицательными номерами)

mysql> use test
Database changed
mysql> drop table if exists swaptest;
Query OK, 0 rows affected (0.03 sec)

mysql> create table swaptest (X int,Y int);
Query OK, 0 rows affected (0.12 sec)

mysql> INSERT INTO swaptest VALUES (1,2),(3,4),(-5,-8),(-13,27);
Query OK, 4 rows affected (0.08 sec)
Records: 4  Duplicates: 0  Warnings: 0

mysql> SELECT * FROM swaptest;
+------+------+
| X    | Y    |
+------+------+
|    1 |    2 |
|    3 |    4 |
|   -5 |   -8 |
|  -13 |   27 |
+------+------+
4 rows in set (0.00 sec)

mysql>

Здесь выполняется своп

mysql> UPDATE swaptest SET X=X+Y,Y=X-Y,X=X-Y;
Query OK, 4 rows affected (0.07 sec)
Rows matched: 4  Changed: 4  Warnings: 0

mysql> SELECT * FROM swaptest;
+------+------+
| X    | Y    |
+------+------+
|    2 |    1 |
|    4 |    3 |
|   -8 |   -5 |
|   27 |  -13 |
+------+------+
4 rows in set (0.00 sec)

mysql>

Дайте ему попробовать !!!

35
ответ дан RolandoMySQLDBA 18 August 2018 в 07:05
поделиться
  • 1
    Для чисел это действительно самый опрятный. – Your Common Sense 23 April 2014 в 17:15
  • 2
    @YourCommonSense Ваша щедрость говорит Роналду, когда это на самом деле Роландо. – Albzi 24 April 2014 в 16:46

Мне нужно было просто переместить значение из одного столбца в другое (например, архивирование) и сбросить значение исходного столбца. Ниже (ссылка № 3 из принятого ответа выше) работала для меня.

Update MyTable set X= (@temp:= X), X = 0, Y = @temp WHERE ID= 999;
0
ответ дан Sandeep 18 August 2018 в 07:05
поделиться

Вы могли изменять имена столбцов, но это скорее хак. Но будьте осторожны с любыми индексами, которые могут быть на этих столбцах

1
ответ дан SeanDowney 18 August 2018 в 07:05
поделиться

Две альтернативы 1. Используйте временную таблицу 2. Изучите алгоритм XOR

4
ответ дан Unsliced 18 August 2018 в 07:05
поделиться

Обмен значениями столбцов с использованием одного запроса

UPDATE my_table SET a = @ tmp: = a, a = b, b = @ tmp;

cheers ...!

0
ответ дан webizon 18 August 2018 в 07:05
поделиться
0
ответ дан Andrew Foster 6 September 2018 в 20:46
поделиться
0
ответ дан Andrew Foster 30 October 2018 в 02:04
поделиться
Другие вопросы по тегам:

Похожие вопросы: