Конференция "Начинающим" » По рекурсивным CTE в Firebird/ [XP]
 
  • Drowsy © (12.04.17 12:46) [0]
    Есть таблица - список слов

    CREATE TABLE TMP_WORDS (
       WORD_NUM       INTEGER NOT NULL,
       WORD_BODY      VARCHAR_255 /* VARCHAR_255 = VARCHAR(255) */,
       NEXT_WORD_NUM  INTEGER
    );

    и таблица объектов с именами

    CREATE TABLE OBJECTS (
       ID            INTEGER NOT NULL,
       NAME          D_NODE_NAME /* D_NODE_NAME = CHAR(1000) */
    );

    задача - выбрать из таблицы объектов те, которые содержать все слова из таблицы списка слов

    Написал такое рекурсивное CTE :

         For
           with recursive
              Check_Words AS
              (
               select
                 t_w.word_num,
                 t_w.next_word_num,

                 objects.id as objects_id,
                 objects.name as objects_name,

                 t_w.word_body

               from tmp_words t_w
                 inner join objects  on (Upper(objects.name) like ('%' || upper(t_w.word_body)  || '%'))
               where (t_w.word_num  = 0)

               UNION ALL

               select
                 t_w.word_num,
                 t_w.next_word_num,

                 objects.id as objects_id,
                 objects.name as objects_name,

                 t_W.word_body

               from tmp_words t_w
                 inner join objects  on (Upper(objects.name) like ('%' || upper(t_w.word_body)  || '%'))
                 inner JOIN Check_Words cc_ww
               ON
                (
                  (t_w.word_num = CC_WW.NEXT_WORD_NUM ) and
                  (
                   objects_id = CC_WW.objects_id
                  )
                )
         )
         select distinct
             FF_WW.objects_id,
             FF_WW.word_num,
             FF_WW.objects_name
         from Check_Words FF_WW
         INTO
             :ob_glos_objects_id,
             :ps,
             :GLOS_WORD_S

         Do
         begin
           if (not (ps is NULL)) then
             if (ps = cnt_wrds - 1) then
               suspend;
         end
         exit;
      end

    В результате получается набор, в котором записи, включающие хотя бы одно слово из таблицы слов,
    т.е., похоже, что требование
               from tmp_words t_w
                 inner join objects  on (Upper(objects.name) like ('%' || upper(t_w.word_body)  || '%'))
                 inner JOIN Check_Words cc_ww
               ON
                (
                  (t_w.word_num = CC_WW.NEXT_WORD_NUM ) and
                  (
                   objects_id = CC_WW.objects_id
                  )
                )
    игнорируется.

    Как это понимать и что исправить?
  • kilkennycat © (12.04.17 13:15) [1]
  • rrrrr © (12.04.17 13:43) [2]
    т.е., похоже, что требование игнорируется.

    сервер не может ничего игнорировать в принципе.
    что ты написал то ты от него и получил.
  • Drowsy © (12.04.17 13:48) [3]

    > rrrrr ©   (12.04.17 13:43) [2]

    Полезное замечание.
  • rrrrr © (12.04.17 14:06) [4]
    однажды один мальчик написал "селект все фром тэйблА",
    но сервер проигнорировал его требование и вернул мальчику все строки из тэйблБэ

    т.е., похоже, что требование
              from tmp_words t_w
                inner join objects  on (Upper(objects.name) like ('%' || upper(t_w.word_body)  || '%'))
                inner JOIN Check_Words cc_ww
              ON
               (
                 (t_w.word_num = CC_WW.NEXT_WORD_NUM ) and
                 (
                  objects_id = CC_WW.objects_id
                 )
               )
    игнорируется.


    с чего вдруг оно игнорируются?
    воочию наблюдаешь строки для которых равенство или лайк не выполняется но в выборке они есть?
  • rrrrr © (12.04.17 14:20) [5]
    select *
    from objects
    where id not in (select id
                         from objects o
                         where exists(select null
                                           from tmp_words
                                           where o.name not like '%' || word_body || '%'
                          )
          )
  • Drowsy © (12.04.17 14:41) [6]

    > rrrrr ©   (12.04.17 14:06) [4]


    > воочию наблюдаешь строки для которых равенство или лайк
    > не выполняется но в выборке они есть?


    Да.
    В результате получается набор, в котором записи, включающие хотя бы одно слово из таблицы слов.
  • rrrrr © (12.04.17 14:47) [7]
    Да.
    В результате получается набор, в котором записи, включающие хотя бы одно слово из таблицы слов.



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

    а что там ты подразумевал в уме промеж строк запроса - про то сервер не в курсе.
  • Drowsy © (12.04.17 14:58) [8]

    > rrrrr ©   (12.04.17 14:47) [7]


    Мне нужно выбрать только те строки, которые содержат все слова , которые в таблице tmp_words.

    Я написал рекурсивное СТЕ для этого.

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

    Что исправить , чтобы выбирались только записи со всеми словами таблицы слов?
  • rrrrr © (12.04.17 15:03) [9]
    Мне нужно выбрать только те строки, которые содержат все слова , которые в таблице tmp_words.
    Я написал рекурсивное СТЕ для этого.


    ну и где там в написанном программируется "только когда все слова" ?

    в [5] - там оно есть.
    находим объекты у которых нет хотя бы одного слова, затем выбираем все объекты которые "не такие"

    а у тебя где?
  • Drowsy © (12.04.17 15:17) [10]

    > rrrrr ©   (12.04.17 15:03) [9]

    То, что, как мне кажется, я написал:
    В первой итерации для первого слова из tmp_words выбираем записи из таблицы objects, в которых поле Name содержит это слово.
    В следующих итерациях Для выбранных в предыдущей  записей ищем второе слово... и т.д.
              from tmp_words t_w
                inner join objects  on (Upper(objects.name) like ('%' ||    upper(t_w.word_body)  || '%'))
                inner JOIN Check_Words cc_ww
              ON
               (
                 (t_w.word_num = CC_WW.NEXT_WORD_NUM ) and
                 (
                  objects_id = CC_WW.objects_id
                 )
               )
    Когда добрались до последнего слова, выводится результирующий набор.
  • rrrrr © (12.04.17 15:30) [11]
    я вижу лайк и равно.

    и все что лайкает и равняется - всё попало в выборку.

    и нет там никаких условий на "когда только лишь все слова"

    и у сервера нет никаких "предыдущих" записей. он берет пару очередных кандидатов на джойн и сравнивает.
    совпало - сует в выборку. не совпало - не сует.

    зачем весь этот трэш и угар?
    к чему там "некст ворд"?
    важен порядок слов?
    ну так юзай лайк и готовую маску "%мама%мыла%раму%"

    порядок слов не важен?
    юзай [5]
  • Drowsy © (12.04.17 15:42) [12]

    > rrrrr ©   (12.04.17 15:30) [11]


    Я деревья высаживаю.
    Там есть задачи на рекурсию.
    Эту "задачку" разбираю для примера, чтобы понять, как работает рекурс.СТЕ

    (t_w.word_num = CC_WW.NEXT_WORD_NUM )  - в эту выборку берётся следующее слово из предыдущей итерации.
    and
    objects_id = CC_WW.objects_id - и только те объекты, которые выбраны в предыдущей итерации(то есть, содержат предыдущие слова).
  • rrrrr © (12.04.17 15:51) [13]
    "руззьке языг сто балл, патступаю мгемо"

    нет никаких "предыдущих" итераций.

    они уже если сработали при сравнении "той итераци", то обжект ид уже в выборке есть.
    и если "следующая" "итерация"не сработает,
    то айдишник, который был добавлен "вчера" в "предыдущей итерации" - его уже никто из выборки не "выкинет".
  • Drowsy © (12.04.17 15:58) [14]
    его уже никто из выборки не "выкинет".

    suspend: Когда добрались до последнего слова, выводится результирующий набор.
  • rrrrr © (12.04.17 16:00) [15]
    с точки зрения эволюции
    было бы правильнее
    если бы деревья высаживали тебя.

    до них кажись уже дошло бы.
  • Drowsy © (12.04.17 16:00) [16]
    "Выполнение  рекурсивного  CTE  с  точки  зрения  сервера  Firebird  можно  описать
    следующим образом:
    • Сервер начинает выполнение с не рекурсивного члена;
    • Для  каждой  выбранной  строки  из  нерекурсивного  части  выполняется  каждый
    рекурсивный  член  один  за  другим,  используя  текущие  значения  из  предыдущей
    итерации как параметры;
    • Если во время выполнения экземпляр рекурсивного элемента не выдаёт строк, цикл
    выполнения переходит на предыдущий уровень и получает следующую строку от
    внешнего для него набора данных."
  • rrrrr © (12.04.17 16:02) [17]
    "Выполнение  рекурсивного  CTE  с  точки  зрения  сервера  Firebird  можно  описать
    следующим образом:


    чувак, скажи мне
    где там написано что если не выполнилось условие скажем только последней итерации, то вся выборка должна быть похерена?
  • rrrrr © (12.04.17 16:12) [18]
    вот тебе на пальцах:
    две таблицы с одним полем name

    мама   мама
    мыла  мыла
    раму  папу

    запрос:

    select a.*
    from a, b
    where a.name = b.name

    по твоей извращенной логике выборка должна быть пустой, потому что в "а" не все строки равны строкам "в"
  • Drowsy © (12.04.17 16:43) [19]
    По-моей логике:

    0 - тебя
    1 - деревья

    11 если бы деревья высаживали тебя.
    15 белый человек очень умный
    22 если бы высаживали тебя баобабы  .

    первая итерация
    0- тебя

    набор 1
    11 - 0
    22 - 0

    вторая
    1 - деревья

    11 - 1

    результирующий:
    ID   WORD_NUM
    11  -  0
    22  -  0
    11  -  1

    For
    Select * from результирующий
    into

    do
    begin
     if Word_Num = 1  then
       suspend
    end

    11  -  1
    11 если бы деревья высаживали тебя.
 
Конференция "Начинающим" » По рекурсивным CTE в Firebird/ [XP]
Есть новые Нет новых   [118654   +11][b:0][p:0.001]