Запятая разделила значения в поле базы данных

Это может быть лишь ограничением реализации директивы. Из документов :

Тип возврата поля подписки в вашей схеме должен совпадать с типом возврата соответствующего поля мутации.

blockquote>

Предполагая, что есть какое-то поле type, которое вы используете, чтобы различать PersonalTask и OtherTask, одним из обходных путей будет подписка на все задачи, но использование аргумент для сужения подписки:

подписка onUpdateTask (тип: String!): Task @aws_subscribe (мутации: ["updateTask"])

6
задан Powerlord 10 April 2009 в 16:31
поделиться

8 ответов

Во-первых, давайте сделаем исходную таблицу такой, как эта:


Id   | Value
-----+------
0001 | IN
0001 | ME
0001 | OH
0001 | ON
0002 | AC
0002 | ON
0002 | VI
0002 | ZO
0003 | ME
0003 | OO
0003 | PS
0003 | QA

Это достигается путем анализа значений, разделенных запятыми в ряды. Затем используйте мощное ключевое слово CROSS APPLY, чтобы объединиться с исходной таблицей, чтобы получить ее идентификатор. Следующий шаг - просто запросить этот CTE.


create function FnSplitToTable
(
    @param nvarchar(4000)
)
returns table as
return
    with
    Num(Pos) as -- list of positions, numbered from 1 to 4000, largest nvarchar
    (
        select cast(1 as int)
        union all 
        select cast(Pos + 1 as int) from Num where Pos < 4000
    )
    select substring(@Param, Pos, 
        charindex(',', @Param + ',', Pos) - Pos) as Value
        from Num where Pos <= convert(int, len(@Param)) 
        and substring(',' + @Param, Pos, 1) = ','
go


create proc ProcGetProductId
(
    @Codes nvarchar(4000)
)
as
with
Src
(
    Id,
    Code
)
as
(
    select '0001', 'IN,ON,ME,OH'
    union all
    select '0002', 'ON,VI,AC,ZO'
    union all
    select '0003', 'QA,PS,OO,ME'
),
Parse as
(
    select 
        s.Id, 
        f.Value
    from 
        Src as s
    cross apply
        FnSplitToTable(s.Code) as f 
)
select distinct 
    p.Id
from 
    Parse as p
join
    FnSplitToTable(@Codes) as f
on
    p.Value = f.Value
option (maxrecursion 4000)
go

exec ProcGetProductId 'IN,ME' -- returns 0001 & 0003
8
ответ дан 8 December 2019 в 02:22
поделиться

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

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

Проще говоря, ядро ​​СУБД не может вести какой-либо быстрый список строк, содержащих код «AC», если вы не разбиваете его на отдельную таблицу или не помещаете в отдельный столбец.

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

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

...
WHERE ',' + Code + ',' LIKE '%,AC,%'

Это будет:

  • Соответствует 'ON, VI, AC, ZO'
  • Не соответствует 'ON, VI, TAC, ZO'

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

...
WHERE Code LIKE '%AC%'

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

если у вас есть только двухбуквенные коды, вы можете использовать только это:

...
WHERE Code LIKE '%AC%'

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

если у вас есть только двухбуквенные коды, вы можете использовать только это:

...
WHERE Code LIKE '%AC%'

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

7
ответ дан 8 December 2019 в 02:22
поделиться

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

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

Если вы попытаетесь пойти по вашему текущему пути: Вам придется разбить входную строку, потому что ничто не гарантирует, что коды в каждой записи находятся в том же порядке (или непрерывно), что и входной параметр. Затем вам нужно будет выполнить запрос

Code LIKE '%IN%'
AND Code Like '%QA%'

с дополнительным оператором для каждого кода, который вы проверяете. Очень неэффективно.

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

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

11
ответ дан 8 December 2019 в 02:22
поделиться

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

4
ответ дан 8 December 2019 в 02:22
поделиться

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

Вот ссылка на такой UDF: FN_Split UDF

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

5
ответ дан 8 December 2019 в 02:22
поделиться

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

ProductCode
-----------
ProductID (FK to Product.ID)
Code (varchar)

Таблица может выглядеть следующим образом:

ProductID    Code
-----------------
0001         IN
0001         ON
0001         ME
...

Запрос будет выглядеть примерно так (вам придется как-то передавать коды - либо в виде отдельных переменных, либо, возможно, запятой разделенная строка в процедуре):

select ProductID
from ProductCode
where Code in ('ON', 'ME')
0
ответ дан 8 December 2019 в 02:22
поделиться

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

Вот пример функции, написанной на диалекте Sybase, которая делает то, что вы делаете:

ALTER FUNCTION "DBA"."f_IsInStringList"( IN @thisItem char(2), IN @thisList varchar(4000) )
RETURNS INTEGER
DETERMINISTIC
BEGIN


DECLARE is_member bit;
DECLARE LOCAL TEMPORARY TABLE tmp (thisItem  char(2)) ;
DECLARE @tempstring varchar(10);
DECLARE @count integer;

IF LENGTH(TRIM(@thisList)) > 0 THEN

    WHILE LENGTH(TRIM(@thisList)) > 0  LOOP
       -- loop over comma-separated list and stuff members into temp table
       IF LOCATE ( @thisList, ',' , 1) > 0 THEN

           SET @count = LOCATE ( @thisList, ',' , 1);
           SET @tempstring = SUBSTRING ( @thisList, 1,@count-1 );

           INSERT INTO tmp ( thisItem  ) VALUES (  @tempstring );
           SET @thisList = STUFF ( @thisList, 1, @count, '' )

        ELSE

            INSERT INTO tmp ( thisItem  ) VALUES ( @thisList );
            SET @thisList = NULL;

        END IF;

    END LOOP ;

END IF;

IF EXISTS (SELECT * FROM tmp WHERE thisItem   = @thisItem ) THEN
    SET is_member = 1;
ELSE
    SET is_member = 0 ;
END IF ;

    RETURN is_member;
END

Затем вы можете создать простой запрос, чтобы проверить, встречается ли значение в строке, разделенной запятыми:

select * from some_table t 
         WHERE f_IsInStringList('OR', t.your_comma_separated_column) = 1 OR
               f_IsInStringList('ME', t.your_comma_separated_column) = 1 
0
ответ дан 8 December 2019 в 02:22
поделиться

Вопрос давности более 1 года, но все же подумал, что он будет полезен. Вы можете использовать функцию FIND_IN_SET MySql. Я не уверен, поддерживают ли это другие СУБД.

Эту функцию можно использовать следующим образом:

SELECT * FROM `table_name` WHERE FIND_IN_SET('AC', `Code`) > 0
4
ответ дан 8 December 2019 в 02:22
поделиться
Другие вопросы по тегам:

Похожие вопросы: