Нахождение строки приводит к разделению строк

#sql

#sql

Вопрос:

У меня есть столбец «Выбранные клиенты» в таблице базы данных, содержащей выбранных клиентов, которые менеджер сейчас редактирует там детали. Например, он может содержать эту строку ‘111,222,333’, что означает, что в данный текущий момент времени менеджер выбран для редактирования клиентов с этими идентификаторами 111,222 и 333. Если другой менеджер пытается отредактировать клиента, который уже редактируется первым менеджером, второй менеджер должен получить сообщение об ошибке, не позволяющее ему редактировать этого клиента. Эта проверка должна выполняться в sql. И допустим, что процедура проверки хранилища получает nvarchard «CheckCustomers» с этим значением: ‘234,222,341’. И поскольку второй менеджер пытается отредактировать клиента с идентификатором 222, который уже выбран для редактирования первым менеджером. Второй менеджер получит сообщение об ошибке. Каким должен быть sql-запрос? (У меня уже есть функция «разделения».)

 SELECT * FROM dbo.test WHERE dbo.Split(SelectedCustomers)IN (CheckCustomers)
  

Комментарии:

1.Я думаю, что вам следует создать SelectedCustomers таблицу вместо столбца, который содержит ManagerID и CustomerID с уникальным ограничением / первичным ключом для CustomerID. Затем должно быть тривиально проверить с помощью запроса к этой таблице, существует ли CustomerID или нет.

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

Ответ №1:

Почему бы просто не добавить еще один столбец ‘IsBeingEdited’ в таблицу клиента? Затем вы можете просто:

 SELECT id FROM customer WHERE id IN (CheckCustomers) AND IsBeingEdited = 1;
  

В списке указаны идентификаторы редактируемого в данный момент клиента, верно (и их легко изменить на другой столбец, например имя)? Таким образом, вы также можете показать это второму менеджеру.

Комментарии:

1. Посмотрите на мой пример; из-за идентификатора клиента 222 второй менеджер не может редактировать всех остальных клиентов. Достаточно, если мы обнаружим, что один клиент уже отредактирован, чтобы запретить второму менеджеру редактировать всех своих всех выбранных клиентов

2. Тогда приведенного выше запроса также достаточно, все, что вам нужно сделать, это проверить, является ли количество возвращаемых строк > 0 или нет. Если да, то по крайней мере один из выбранных клиентов редактируется другим менеджером.

Ответ №2:

Вы можете сделать это с помощью CROSS APPLY .

 IF EXISTS (
    SELECT S.CustomerID
    FROM dbo.test T
    CROSS APPLY dbo.Split(T.SelectedCustomers) S
    CROSS APPLY dbo.Split(T.CheckCustomers) C
    WHERE S.CustomerID = C.CustomerID
)
BEGIN
    RAISERROR('Customer is locked by another user', 16, 0)
END
  

Ответ №3:

Я предлагаю изменить этот дизайн. Каждый раз, когда необходимо делать что-то вроде разделения строк, чтобы получить доступ к «скрытым» полям внутри строки, это является нарушением одного из основных принципов использования реляционной базы данных, который заключается в том, что каждое поле в строке должно хранить единственное значение. Можно ли заставить это работать? Вероятно. Хорошая ли это идея сделать это? На мой взгляд, нет.

Как указывали другие, существует несколько способов изменить дизайн. В таблицу Customer может быть добавлен столбец, указывающий, что клиент заблокирован. Можно было бы использовать отдельную таблицу (например, CustomerLocked), содержащую CustomerID и идентификатор менеджера — это позволило бы добавить дополнительную информацию, такую как время, в течение которого клиент был заблокирован, и т.д., Что Может быть полезно, если кто-то заблокирует клиента, а затем уйдет из-за своего стола.

Я полагаю, что любое из этих изменений удовлетворит требованиям. Например, предположим, что создана таблица LockedCustomer:

 Table LockedCustomer
  CustomerID    NUMBER  PRIMARY KEY
  ManagerID     VARCHAR
  AddDate       DATE
  

и предположим, что менеджер A заблокировал клиентов 111, 222 и 333; таким образом, в таблице LockedCustomer будут существовать следующие строки:

 CustomerID      ManagerID
111             A
222             A
333             A
  

Теперь приходит менеджер B, который хочет заблокировать клиента 222. Диспетчер приложений B использует попытки вставить новую строку в таблицу LockedCustomer следующим образом:

 INSERT INTO LockedCustomer (CustomerID, ManagerID)
  VALUES (222, 'B');
  

Эта инструкция должна завершиться ошибкой, потому что CustomerID 222 уже существует в таблице, а столбец CustomerID является первичным ключом в LockedCustomer. Это имеет смысл, поскольку мы хотим, чтобы данный CustomerID существовал не более одного раза в таблице LockedCustomer в любой момент времени. Затем используемый диспетчер приложений B мог бы обнаружить, что вставка не удалась из-за нарушения ограничения первичного ключа, и понял бы, что это означало, что клиент не может быть заблокирован в это время. Путем повторного запроса таблицы LockedCustomer для получения дополнительных данных, как в:

 SELECT *
  FROM LockedCustomer
  WHERE CustomerID = 222
  

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

 The customer you wished to edit (222) is currently in use
by Manager A since 03-Jun-2011 2:17 PM.  Would you like to
  A) Wait
  B) Send an email to Manager A
  C) Take a long vacation
  D) Violate company policy regarding alcohol consumption
     during working hours
Please select one of the above options?
  

Делитесь и наслаждайтесь.

Комментарии:

1. Я хотел бы предложить и это, но реструктуризация базы данных может оказаться невозможной для операционной системы, поэтому я рассматриваю другое решение. Кроме того, каждый клиент может редактироваться только одним менеджером одновременно. Таким образом, это скорее отношение 1-n, чем m-n.

2. @LeleDumbo: ваши замечания хорошо учтены. Пожалуйста, обратите внимание, что при том, как настроена таблица LockedCustomer, только один пользователь одновременно может заблокировать клиента (т. Е. CustomerID является первичным ключом в LockedCustomer). Спасибо.