2016-08-12 2 views
1

Сначала у нас есть код, и после этого у нас есть реальный вопрос.Логика SQL Server, для которой набор данных в наборе данных

Функция для разделения строк. Я нашел это где-то в Интернете, и я еще не потрудился проверить его качество. Я только добавляю функцию здесь, чтобы сделать вопрос более полным.

CREATE FUNCTION [dbo].[Split] (
     @InputString     NVARCHAR(4000), 
     @Delimiter     NVARCHAR(50) 
) 

RETURNS @Items TABLE (
     Item       NVARCHAR(4000) 
) 

AS 
BEGIN 
     IF @Delimiter = ' ' 
     BEGIN 
      SET @Delimiter = ',' 
      SET @InputString = REPLACE(@InputString, ' ', @Delimiter) 
     END 

     IF (@Delimiter IS NULL OR @Delimiter = '') 
      SET @Delimiter = ',' 

--INSERT INTO @Items VALUES (@Delimiter) -- Diagnostic 
--INSERT INTO @Items VALUES (@InputString) -- Diagnostic 

     DECLARE @Item     NVARCHAR(4000) 
     DECLARE @ItemList  NVARCHAR(4000) 
     DECLARE @DelimIndex  INT 

     SET @ItemList = @InputString 
     SET @DelimIndex = CHARINDEX(@Delimiter, @ItemList, 0) 
     WHILE (@DelimIndex != 0) 
     BEGIN 
      SET @Item = SUBSTRING(@ItemList, 0, @DelimIndex) 
      INSERT INTO @Items VALUES (@Item) 

      -- Set @ItemList = @ItemList minus one less item 
      SET @ItemList = SUBSTRING(@ItemList, @DelimIndex+1, LEN(@ItemList)[email protected]) 
      SET @DelimIndex = CHARINDEX(@Delimiter, @ItemList, 0) 
     END -- End WHILE 

     IF @Item IS NOT NULL -- At least one delimiter was encountered in @InputString 
     BEGIN 
      SET @Item = @ItemList 
      INSERT INTO @Items VALUES (@Item) 
     END 

     -- No delimiters were encountered in @InputString, so just return @InputString 
     ELSE INSERT INTO @Items VALUES (@InputString) 

     RETURN 

END -- End Function 
GO 

И вот у нас есть мой код. Код был изменен для простоты.

CREATE TABLE dbo.[Rule] (
    RuleID INT, 
    RuleCode NVARCHAR(255), 
    RuleFormula NVARCHAR(MAX), 
    TableKey INT, 
    RelatedTables NVARCHAR(1000) 
); 

INSERT INTO dbo.[rule] (RuleID, RuleCode, RuleFormula, TableKey, RelatedTables) 
SELECT 1, 'Code1', 'Someformula', 1, 'TableA|TableB|TableC|TableD' 
UNION ALL 
SELECT 2, 'Code2', 'Someformula', 1, 'TableA|TableB|TableC' 
UNION ALL 
SELECT 3, 'Code3', 'Someformula', 1, 'TableA|TableB'; 
GO 

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

CREATE PROCEDURE [dbo].[RuleGet] 
@TableKey INT = NULL 
AS 
BEGIN 

DECLARE @RelatedTables TABLE (
    RelatedTableCode NVARCHAR(255) 
); 

INSERT INTO @RelatedTables (RelatedTableCode) 
SELECT 'TableA' 
UNION ALL 
SELECT 'TableB' 
UNION ALL 
SELECT 'TableC'; 

SELECT 
    RuleId, 
    RuleCode, 
    RuleFormula 
FROM [dbo].[Rule] 
WHERE @TableKey = TableKey 
AND (SELECT item FROM [dbo].[Split](RelatedTables, '|')) IN (SELECT RelatedTableCode FROM @RelatedTables); 

END 
GO 

То, что я хочу добиться того, что правила, возвращаемых хранимой процедурой следует отфильтровать по TableKey (как это делает), но и при условии, что правило должно быть извлечено, только если все RelatedTable кодов, для этого правила существуют в списке @RelatedTables.

В этом примере я хочу, чтобы правила 2 и 3 возвращались хранимой процедурой.

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

Мы используем стандартную версию SQL Server 2014.

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

+0

Поиск «реляционного деления в SQL». –

ответ

1

Если вы можете гарантировать, что значения в Rule.RelatedTables содержат имена таблиц в алфавитном порядке, вы можете сделать это:

SELECT 
     RuleId, 
     RuleCode, 
     RuleFormula 
    FROM [dbo].[Rule] 
    WHERE @TableKey = TableKey 
    AND CHARINDEX(RelatedTables, (SELECT STUFF((SELECT '|' + RelatedTableCode 
               FROM @RelatedTables 
               GROUP BY RelatedTableCode 
               ORDER BY RelatedTableCode 
               FOR XML PATH('') 
               ), 1, 1, ''))) <> 0 

Это эффективно уплотняет содержимое переменной @RelatedTables в том же формате, что и значения в Rule.RelatedTables, затем проверяет, является ли последнее подстрокой первого, что, я считаю, должно дать вам поведение, которое вы хотите.

Для этого я определенно не буду этого делать (даже если я думаю, что могу гарантировать порядок значений, закодированных в Rule.RelatedTables), я бы, вероятно, создал функцию, которая принимает два параметра (@RelatedTables переменная таблицы и varchar, содержащая значение Rule.RelatedTables) и оценивает их друг против друга процедурно (как вы намекаете в своем вопросе), возвращая логическое значение, чтобы указать, соответствуют ли они достаточно или нет.