SQL-запрос и присоединение: почему? - PullRequest
1 голос
/ 13 марта 2011

Извините, если это вопрос новичка, но, похоже, я не понимаю, почему это не работает так, как хотелось бы:

mysql> select t.id,t.date_fin_val,tc.date_fin_val
from tiers t
join tiers_critere_int tc on tc.id_tiers=t.id
where (t.date_fin_val is null) and (tc.date_fin_val is null);
+----+---------------------+---------------------+
| id | date_fin_val        | date_fin_val        |
+----+---------------------+---------------------+
|  1 | 0000-00-00 00:00:00 | 0000-00-00 00:00:00 | 
|  1 | 0000-00-00 00:00:00 | 0000-00-00 00:00:00 | 
|  1 | 0000-00-00 00:00:00 | 0000-00-00 00:00:00 | 
+----+---------------------+---------------------+
3 rows in set (0.00 sec)

mysql> select t.id,t.date_fin_val,tc.date_fin_val
from tiers t
left outer join tiers_critere_int tc on tc.id_tiers=t.id
where (t.date_fin_val is null) and (tc.date_fin_val is null);
Empty set (0.00 sec)

mysql> 

Я думал, что «левые внешние соединения» означают: «если нет результата с правой стороны, кроме одного слева, продолжайте в любом случае с левым и вставьте» null "значения справа. Если я был прав, второй запрос с "left outer join" вместо "join" должен возвращать значения. Но это не так. Почему?

Вот мои данные:

mysql> select * from tiers t where date_fin_val is null;
+----+---------------------+--------------------+
| id | date_fin_val        | est_tiers_physique |
+----+---------------------+--------------------+
|  1 | 0000-00-00 00:00:00 |                  1 | 
+----+---------------------+--------------------+
1 row in set (0.00 sec)

mysql> select * from tiers_critere_int  where date_fin_val is null;
+----+---------------------+----------+------------+---------+
| id | date_fin_val        | id_tiers | id_critere | critere |
+----+---------------------+----------+------------+---------+
|  1 | 0000-00-00 00:00:00 |        1 |          2 |      86 |
|  2 | 0000-00-00 00:00:00 |        1 |          6 |     170 |
|  3 | 0000-00-00 00:00:00 |        1 |          7 |      65 |
+----+---------------------+----------+------------+---------+
3 rows in set (0.00 sec)

mysql>

Большое спасибо!

Ответы [ 5 ]

1 голос
/ 13 марта 2011

Кажется, в MySQL есть ошибка.Вот как я создал свои таблицы:

CREATE TABLE tiers_critere_int (
  id bigint AUTO_INCREMENT NOT NULL,
  date_debut_val datetime not null,
  date_fin_val datetime **default NULL**,
  id_tiers bigint(20) NOT NULL,
  id_critere bigint(20) NOT NULL,
  critere bigint(20) NOT NULL,
  PRIMARY KEY  (id,date_debut_val,date_fin_val),
  KEY id (id),
  KEY date_debut_val (date_debut_val),
  KEY date_fin_val (date_fin_val),
  KEY date_debut_val_2 (date_debut_val,date_fin_val),
  KEY critere (critere),
  KEY id_tiers (id_tiers),
  KEY id_critere (id_critere),
  FOREIGN KEY (id_tiers) REFERENCES tiers (id)
  ON UPDATE CASCADE ON DELETE CASCADE,
  FOREIGN KEY (id_critere) REFERENCES critere (id)
  ON UPDATE CASCADE ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

В tiers_critere_int, date_fin_val по умолчанию равно нулю .Это то, что ты думаешь.Но если вы сделаете:

mysql> update tiers_critere_int set date_fin_val= null;
Query OK, 0 rows affected, 3 warnings (0.00 sec)
Rows matched: 3  Changed: 0  Warnings: 3

mysql> show warnings;
+---------+------+--------------------------------------+
| Level   | Code | Message                              |
+---------+------+--------------------------------------+
| Warning | 1048 | Column 'date_fin_val' cannot be null | 
| Warning | 1048 | Column 'date_fin_val' cannot be null | 
| Warning | 1048 | Column 'date_fin_val' cannot be null | 
+---------+------+--------------------------------------+
3 rows in set (0.00 sec)

mysql> 

Проблема заключается в том, что MySQL допускает создание таблицы, но не принимает нулевые значения для ключей.Но что не является нормальным, так это то, что этот запрос работает, и это явно удивительно (или не нормально, это вам решать):

mysql> select * from tiers_critere_int
where date_fin_val is null;
+----+---------------------+---------------------+----------+------------+---------+
| id | date_debut_val      | date_fin_val        | id_tiers | id_critere | critere |
+----+---------------------+---------------------+----------+------------+---------+
|  1 | 2011-03-13 06:07:05 | 0000-00-00 00:00:00 |        1 |          2 |      86 | 
|  2 | 2011-03-13 06:07:05 | 0000-00-00 00:00:00 |        1 |          6 |     170 | 
|  3 | 2011-03-13 06:07:05 | 0000-00-00 00:00:00 |        1 |          7 |      65 | 
+----+---------------------+---------------------+----------+------------+---------+
3 rows in set (0.00 sec)

mysql> 

Так что это действительно сбивает с толку, и что более запутанно, так это то, чтопредложение "is null" правильно обрабатывается в предложении where (t.date_fin_val is null), но оно не обрабатывается должным образом в предложении and (tci.date_fin_val is null), тогда как в запросе то же самое , для таблиц, созданных то же самое Кстати, на те же столбцы.

Итак, конец истории: правильный запрос :

mysql> select t.id,t.date_fin_val,tci.date_fin_val
from tiers t
left outer join tiers_critere_int tci
on t.id=tci.id_tiers
where (t.date_fin_val ='0000-00-00 00:00:00')
and (tci.date_fin_val ='0000-00-00 00:00:00');
+----+---------------------+---------------------+
| id | date_fin_val        | date_fin_val        |
+----+---------------------+---------------------+
|  1 | 0000-00-00 00:00:00 | 0000-00-00 00:00:00 |
|  1 | 0000-00-00 00:00:00 | 0000-00-00 00:00:00 |
|  1 | 0000-00-00 00:00:00 | 0000-00-00 00:00:00 |
+----+---------------------+---------------------+
3 rows in set (0.00 sec)

mysql> 
1 голос
/ 13 марта 2011

Мои результаты верны с вашими данными и запросами.

CREATE TABLE `tiers` (
  `id` int(11) DEFAULT NULL,
  `date_fin_val` datetime DEFAULT NULL,
  `est_tiers_physique` int(11) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1

insert into tiers (id, est_tiers_physique) values (1, 1);

select * from tiers;
+------+--------------+--------------------+
| id   | date_fin_val | est_tiers_physique |
+------+--------------+--------------------+
|    1 | NULL         |                  1 |
+------+--------------+--------------------+
1 row in set (0.00 sec)

CREATE TABLE `tiers_critere_int` (
  `id` int(11) DEFAULT NULL,
  `date_fin_val` datetime DEFAULT NULL,
  `id_tiers` int(11) DEFAULT NULL,
  `id_critere` int(11) DEFAULT NULL,
  `critere` int(11) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1

insert into tiers_critere_int (id, id_tiers, id_critere, critere) 
values 
(1, 1, 2, 86),
(2, 1, 6, 170),
(3, 1, 7, 65)
;

select * from tiers_critere_int;
+------+--------------+----------+------------+---------+
| id   | date_fin_val | id_tiers | id_critere | critere |
+------+--------------+----------+------------+---------+
|    1 | NULL         |        1 |          2 |      86 |
|    2 | NULL         |        1 |          6 |     170 |
|    3 | NULL         |        1 |          7 |      65 |
+------+--------------+----------+------------+---------+
3 rows in set (0.00 sec)

select t.id,t.date_fin_val,tc.date_fin_val
from tiers t
join tiers_critere_int tc on tc.id_tiers=t.id
where (t.date_fin_val is null) and (tc.date_fin_val is null);
+------+--------------+--------------+
| id   | date_fin_val | date_fin_val |
+------+--------------+--------------+
|    1 | NULL         | NULL         |
|    1 | NULL         | NULL         |
|    1 | NULL         | NULL         |
+------+--------------+--------------+
3 rows in set (0.00 sec)

select t.id,t.date_fin_val,tc.date_fin_val
from tiers t
left outer join tiers_critere_int tc on tc.id_tiers=t.id
where (t.date_fin_val is null) and (tc.date_fin_val is null);
+------+--------------+--------------+
| id   | date_fin_val | date_fin_val |
+------+--------------+--------------+
|    1 | NULL         | NULL         |
|    1 | NULL         | NULL         |
|    1 | NULL         | NULL         |
+------+--------------+--------------+
3 rows in set (0.02 sec)

Теперь, если вы вставите пустую строку, у вас будет:

insert into tiers (id, date_fin_val, est_tiers_physique) values (2, '', 1);
Query OK, 1 row affected, 1 warning (0.00 sec)

select * from tiers;
+------+---------------------+--------------------+
| id   | date_fin_val        | est_tiers_physique |
+------+---------------------+--------------------+
|    1 | NULL                |                  1 |
|    2 | 0000-00-00 00:00:00 |                  1 |
+------+---------------------+--------------------+
2 rows in set (0.00 sec)
0 голосов
/ 13 марта 2011

Woa --- Я думаю, что вы все что-то упустили:

Это текущее левое соединение:

mysql> select t.id,t.date_fin_val,tc.date_fin_val
from tiers t
left outer join tiers_critere_int tc on tc.id_tiers=t.id
where (t.date_fin_val is null) and (tc.date_fin_val is null);

Вероятно, условие левого соединения должно быть таким:

mysql> select t.id,t.date_fin_val,tc.date_fin_val
from tiers t
left outer join tiers_critere_int tc on tc.id_tiers=t.id AND (tc.date_fin_val is null)
where (t.date_fin_val is null);

Тот факт, что вы по-прежнему фильтровали строки в предложении WHERE, скрывает то, что вы пытаетесь сделать с вашим LEFT OUTER JOIN.

0 голосов
/ 13 марта 2011

LEFT OUTER JOIN с тем же условием и теми же данными должны возвращать больше или такое же количество строк, как INNER JOIN.

Пожалуйста, проверьте:

  1. Ваши данные, чтобы увидеть, совпадают ли они для двух запросов
  2. Являются ли эти два запроса такими, как вы указали в вопросе (например, сделали ли вы опечатку)
0 голосов
/ 13 марта 2011

Я думаю, что это связано с , как MySQL оптимизирует ВЛЕВО (и ВПРАВО) СОЕДИНЕНИЯ в сочетании со столбцами даты, равными NULL.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...