Есть ли альтернатива для XML PATH в SQL - PullRequest
0 голосов
/ 11 января 2020

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

Я использую хитрость, которая заключается в том, что я просто создаю строку в служебной таблице, в которой идентификаторы строки разделены запятой (что-то вроде этого 1,3,7,) и работает нормально, за исключением одного случая.
Это тот случай, когда я хочу отобразить использованные имена элементов в виде одного столбца для нескольких служб.
Я получаю элементы обслуживания один плюс сервис два и так далее, как одна строка для всех услуг.
Есть ли способ, которым я могу решить это? Я знаю, это звучит сложно, но если это сработает, многие другие вы прочтут это.

Я использую для присоединения:

on CHARINDEX(CAST(TblSupply.IDSupply as varchar(10)), TblService.UsedSupplyIDs) > 0  

Просто я разыгрываю идентификатор использованного предмета TblSupply.IDSupply в качестве строки, а затем проверьте, существует ли она в таблице служб.

Когда я отображаю отдельные столбцы, все работает нормально, но я получаю несколько строк для одной и той же службы следующим образом:

Select
  TblService.ServiceName,
  TblSupply.SupplyName
from
  TblService
  left join TblSupply on CHARINDEX(CAST(TblSupply.IDSupply as varchar(10)), TblService.UsedSupplyIDs) > 0   

например

 _____________________________________________
|TblService.ServiceName|TblSupply.SupplyName |
|Patient examination   |Glove                |
|Patient examination   |wood stick           |
|Patient examination   |thermometer          |
|Sonar   examination   |Glove                |
|Sonar   examination   |lubricating Gel      |
|Consultation          |Glove                |
|______________________|_____________________|

Я хочу получить

________________________________________________________
|TblService.ServiceName|xxxxx                           |
|Patient examination   |Glove ,wood stick , thermometer |
|Sonar   examination   |Glove,lubricating Gel           |
|Consultation          |Glove                           |

Код, который я сделал

Select
   TblService.ServiceName,TempTable.SupplyList
from
   TblService
   left join (Select TblService.IDService As IDService,
                     STUFF((Select ', ' + TblSupply.SupplyName
                            FROM
                              TblService
                              left join TblSupply on CHARINDEX(CAST(TblSupply.IDSupply as varchar(10)), TblService.UsedSupplyIDs) > 0
                              FOR XML PATH('')), 1, 1, '') as SupplyList
              FROM
                  TblService
              GROUP BY
                  TblService.IDService
             ) as TempTable on TempTable.IDService=TblService.IDService  

Я пытался

Select
    TblPatientService.IDPatientService,
    TblService.ServiceName,
    TempTable.SupplyList
from
    TblPatientService
    left Join TblService On TblService.IDService = TblPatientService.IDService 
    left join (Select TblPatientService.IDPatientService As IDPatientService
                      STUFF((Select ', ' + TblSupply.SupplyName
                             FROM
                                TblPatientService
                                left join TblService on TblService.IDService = TblPatientService.IDService
                                left join TblSupply on CHARINDEX(CAST(TblSupply.IDSupply as varchar(10)), TblService.UsedSupplyIDs) > 0
                             WHERE
                                TblPatientService.IDService = TblService.IDService
                             FOR XML PATH('')), 1, 1, '') as SupplyList
               FROM
                   TblPatientService
                   left Join TblService On TblService.IDService = TblPatientService.IDService
               GROUP BY
                   TblPatientService.IDPatientService
              ) as TempTable on TempTable.IDPatientService = TblPatientService.IDPatientService  

Что я действительно получаю

|TblService.ServiceName|xxxxx                                                                         
|Patient examination   |Glove ,wood stick , thermometer,Glove,lubricating Gel,Glove,lubricating Gel   |
|Sonar   examination   |Glove ,wood stick , thermometer,Glove,lubricating Gel,Glove,lubricating Gel   |
|Consultation          |Glove ,wood stick , thermometer,Glove,lubricating Gel,Glove,lubricating Gel   |

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

Ответы [ 2 ]

1 голос
/ 11 января 2020

Это слишком долго для комментария.

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

В качестве примера: ваше текущее условие соединения не будет соответствовать ожидаемым для некоторых идентификаторов поставок, которые более одного di git long (обычно 1 соответствует 10).

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

1 голос
/ 11 января 2020

Начиная с SQL Server 2017, вы можете использовать STRING_AGG. Что-то вроде:

SELECT TblPatientService.IDPatientService AS IDPatientService, 
       STRING_AGG(TblSupply.SupplyName, ', ') AS SupplyList
FROM   TblPatientService
       LEFT OUTER JOIN TblService ON TblService.IDService = TblPatientService.IDService
       LEFT OUTER JOIN TblSupply ON CHARINDEX(CAST(TblSupply.IDSupply AS VARCHAR(10)), TblService.UsedSupplyIDs) > 0
GROUP BY TblPatientService.IDPatientService;

Чтобы заменить XML материал!

...