SQL ИЛИ возвращает оба выражения - PullRequest
0 голосов
/ 14 июля 2020

у меня есть хранимая SQL процедура, в которой я хочу присоединиться к другой таблице в зависимости от результатов COALESCE или OR, но почему-то кажется, что coalesce возвращает оба выражения.

Usecase: Если расписание для плейлиста отсутствует -> вернуть расписание по умолчанию (24/7). Это работает как шарм, и я получаю расписание с идентификатором 1. Но если есть расписание, процедура возвращает оба расписания. : - (

Это мой код:

...
RIGHT JOIN schedule
ON COALESCE(playlists.ID = schedule.PLID,playlists.SCHEDULES_ID=1)
WHERE devices.IDENTIFIER = ParamID;

Есть предложения?

THX заранее!

Peter

ОБНОВЛЕНИЕ

Похоже, что coalesce - неправильное решение для моего случая. Есть ли у кого-нибудь предложения?

У меня есть таблица "расписания", в которой есть столбец "PLID" (PlaylistID). В моем запросе я хочу присоединиться к этой таблице на основании этого значения. Если нет расписания с подходящим PLID, я хочу присоединиться к расписанию по умолчанию (ID = 1).

ОБНОВЛЕНИЕ 2

Сейчас я пробую новый подход, который, похоже, все еще не работает. Если расписания нет, я получаю расписание по умолчанию (ID1). Если есть расписание -> я получаю по умолчанию + фактически назначенное расписание (PLID = playlists.ID)

LEFT JOIN schedule
ON (schedule.PLID=playlists.ID) 
OR (schedule.ID = '1')

Ответы [ 2 ]

0 голосов
/ 14 июля 2020

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

Очень сложно сказать вам, почему ваш запрос не выполняется, потому что вы не включили достаточно данных образца, но я постараюсь и изобрести

playlists.ID  playlists.schedulesID  playlist.name
1             1                      default playlist schedule holder
2             100
3             null

schedule.ID  schedule.PLID  schedule.name
X            1              default 247 schedule                   
Y            2            custom schedule 100
Z            null           nully schedule


     COALESCE(playlists.ID=schedule.PLID,playlists.SCHEDULES_ID=1)
1,X  true on 1st argument, row shows
1,Y  false on 1, row hides
1,Z  null on 1, true on 2, row shows
2,X  false on 1, row hides
2,Y  true on 1, row shows
2,Z  null on 1, false on 2, row hides
3,X  false on 1, false on 2, row hides
3,Y  false on 1, false on 2, row hides 
3,Z null on 1, null on 2, row hides

Обратите внимание на истинность, установленную для первой - две строки имеют истину, поэтому 1, X и 1, Z показывают, что дает "повторяющуюся" строку 1

Ввод логического выражение внутри вашего COALESCE - это то, что вам, вероятно, сойдет с рук только mysql, может быть Postgres. Oracle и sqlserver этого не допустит. Однако это не совсем причина проблемы; logi c предоставления значения по умолчанию не работает, потому что он не пытается поместить значения по умолчанию в ту же строку, что и строка, в случае, если строка отсутствует

Лучше бы вы что-то сделали например:

SELECT 
  COALESCE(a.x, d.x) as x,
  COALESCE(a.y, d.y) as y
FROM
  tableWithAllRows a
  LEFT JOIN
  tableWithSomeRows s ON a.id = s.id

  CROSS JOIN
  (
    SELECT * FROM sometable WHERE ID = -1 --values in row is -1 are defaults
  ) d
    

Обратите внимание, что здесь мы специально выполняем соединение с внешним, чтобы допускать отсутствие данных, затем мы используем перекрестное соединение, которое всегда будет успешным и гарантирует, что подзапрос содержит только одну строку. Это означает, что для каждой строки внешнего соединения доступна строка по умолчанию. Мы используем coalesce для извлечения значений по умолчанию, а не для объединения.

Edit; Вы, кажется, указали, что не понимаете этого, поэтому я приведу другой пример с отношением, которое легче понять

Дома у вас есть хранилище для еды. Иногда хранилище - это шкаф, иногда - холодильник. У пищевых продуктов может быть определенное место хранения или место по умолчанию:

ID, Name 
1, Cupboard
2, Refrigerator

Food, Name, StorageID
A, Milk, 2
B, Cereal, 1
C, Beer, null

Молоко идет в холодильник, хлопья в шкафу, пиво не указано (мы будем использовать его по умолчанию). Вы в порядке с этим:

SELECT * FROM
  storage s
  LEFT JOIN food f ON f.StorageID = s.ID

Пиво оказывается нулевым для хранения, потому что для него не установлен StorageID. Вы решаете, что по умолчанию он будет храниться в шкафу:

SELECT * FROM
  storage s
  LEFT JOIN food f 
  ON 
    f.StorageID = s.ID OR
    s.ID = 1 --default to cupboard

Это отлично подходит для хлопьев, потому что StorageID = ID, ох, а также s.ID = 1 тоже верно, но вы не можете " вернее »- ИЛИ просто верно или верно, оба условия верны для злаков, поэтому злаки приходят один раз

B,Cereal,1,1,Cupboard

Все тоже хорошо для пива. StorageID имеет значение null, поэтому StorageID = ID неверно, но ID = 1 верно:

C,Beer,null,1,Cupboard

Пока все хорошо! Но с Milk все разваливается:

A,Milk,2,2,Refrigerator --Milk goes in the fridge because StorageID=ID
A,Milk,2,1,Cupboard     --oh no

Эта строка Oh No появляется, потому что вы указали ID=1 для значения по умолчанию - и вы можете видеть, что это правда! В этой строке действительно есть id1, шкаф. Ничто в нашем предложении ON не препятствует его появлению. Возможно, мы могли бы изменить запрос:

SELECT * FROM
  storage s
  LEFT JOIN food f 
  ON 
    f.StorageID = s.ID OR
    (f.storageID IS NULL AND s.ID = 1) --default to cupboard if no storage id 

Он будет работать, пока вы не наберете:

D,Wine,3

Что такое ID хранилища 3? Без понятия; его нет в таблице, но его приносит левое соединение. 3 также не является нулем, поэтому строка в итоге выглядит так:

D,Wine,3,null,null

Теперь мы застряли. Нет способа решить эту проблему, потому что ваша более ранняя попытка ввести значение по умолчанию действительно принесла значение по умолчанию для пива, но принесла дополнительное значение для Cereal, которое было второй строкой (не связанной с первой). Мы пытались сквашить sh его, добавив больше вещей в наше ПО, но что бы мы ни делали, что-то будет go неправильно

Вместо использования ИЛИ, которое вызовет больше строк в некоторых В некоторых случаях нам нужен еще один JOIN, чтобы получить больше столбцов , и мы позаботимся о том, чтобы в этих столбцах были значения, которые мы выбираем по умолчанию, если реальных данных нет:

SELECT * FROM
  storage s
  LEFT JOIN food f 
  ON 
    f.StorageID = s.ID

  CROSS JOIN 
  (SELECT * FROM storage WHERE ID = 1) def

См. как мы добавили еще одно соединение, а затем вытащили только одну строку из таблицы хранения (строка шкафа). Перекрестное соединение означает, что это будет повторяться в каждой строке.

Теперь данные выглядят так:

A,Milk,2,2,Refrigerator,2,Cupboard
B,Cereal,1,1,Cupboard,2,Cupboard
C,Beer,null,null,null,2,Cupboard
D,Wine,3,null,null,2,Cupboard

Видите значения по умолчанию в последних двух столбцах? Теперь мы можем использовать coalesce, чтобы попытаться сначала получить назначенное местоположение, а затем - местоположение по умолчанию:

SELECT COALESCE(s.Name,def.Name)

Для Milk это холодильник возврата. Для пива он сначала находит значение null, поэтому возвращается к значениям по умолчанию и возвращает это значение.

И тогда вы понимаете, что пиво и вино лучше всего в холодильнике, потому что после всего этого вам понадобится прохладное. Измените подзапрос на «where ID = 2»

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

Третий способ сделать это - пронумеровать строки с указанием c одна имеет приоритет (нижняя строка number) по умолчанию, а затем только строки «приоритет 1»

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

Решите, есть ли в одном списке воспроизведения несколько расписаний или в одном расписании несколько списков воспроизведения. Если несколько списков воспроизведения имеют несколько расписаний, разбейте его на два отношения 1: M с помощью таблицы расписаний списков воспроизведения

0 голосов
/ 14 июля 2020
• 1000 1004 *
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...