Можно ли фильтровать строки в запросе запросов, используя значение свойства значения столбца структуры?

Если объект, такой как Array или Struct, используется в качестве значения столбца строки в объекте запроса CF. Можно ли использовать свойства этого объекта в предложении WHERE запроса запросов для ограничения набора результатов?

Дано:

<cfset local.exampleArray=[
    {   id:1,
        nestedArray:["Tom","Dick","Harry"],
        nestedStruct:{nid:42,name:"unknown"}
    },
    {   id:2,
        nestedArray:["John","Paul","Ringo","George"],
        nestedStruct:{nid:12,name:"rockstars"}
    },
    {   id:3,
        nestedArray:["Bonny","Clyde"],
        nestedStruct:{nid:43,name:"criminals"}
    },
]>
<cfset local.exampleQuery=queryNew("id,nestedArray,nestedStruct","integer,object,object",local.exampleArray)>

Запросы запросов:

<cfquery dbtype="query" name="local.exampleQoQ">
    SELECT *
    FROM   [local].exampleQuery
    WHERE  nestedStruct.nid=12
</cfquery>

<cfquery dbtype="query" name="local.exampleQoQ2">
    SELECT *
    FROM   [local].exampleQuery
    WHERE  nestedArray.length=3
</cfquery>

Приводит к ошибке выполнения запроса запросов: nestedStruct.nid/nestedArray.length не соответствует ни одной таблице в списке таблиц FROM.

Если не использовать столбцы типа объекта в предложении WHERE, объекты возвращаются правильно при запросе и ведут себя так, как ожидалось:

<cfquery dbtype="query" name="local.exampleQoQ">
    SELECT *
    FROM   [local].exampleQuery
    WHERE  id=1
</cfquery>
<cfoutput query="local.exampleQoQ">
    #local.exampleQoQ.id#:#ArrayLen(local.exampleQoQ.nestedArray)#:#local.exampleQoQ.nestedStruct.nid#
</cfoutput>

В результате получится "1:3:42"

Является ли это просто проблемой, когда реализация QoQ не поддерживает доступ к свойствам объекта значения столбца?


person C.J. Scupski    schedule 03.05.2019    source источник
comment
Вы сами ответили на свой вопрос: он просто не поддерживается. Вы всегда можете обойти это, сгладив данные, которые вам нужно запросить/отфильтровать.   -  person Alex    schedule 03.05.2019
comment
Это то, о чем я подумал, прочитав документацию, надеялся, что мне просто не хватает какой-то неясной записи для QoQ. Спасибо за предложение, вероятно, в конечном итоге мы будем использовать ArrayMap, ArrayToList и цикл сбора, чтобы все сгладить.   -  person C.J. Scupski    schedule 03.05.2019
comment
@ CJScupski Это кажется надуманной проблемой. Вы пытаетесь работать с базовым запросом, который возвращает массивы и структуры? И если да, то с какой СУБД вы работаете. Это не похоже на то, что вы хотели бы делать в запросе. Такая структура данных должна быть более плоской. Это можно сделать, но, вероятно, не следует по этой причине здесь. Тем не менее, то, что вы хотите сделать, может быть достигнуто с помощью QueryFilter(), если вы используете CF2016+. Ожидается ответ.   -  person Shawn    schedule 04.05.2019


Ответы (1)


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

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

Вам не нужен Query of Query для этого. Это уже очень ограниченный аспект «запроса» CF, и его следует использовать только при необходимости. Если вы используете ColdFusion 2016+, вы можете использовать добавленную функцию: queryFilter().

Используя приведенную выше настройку в разделе «Дано:», вы можете использовать следующее:

<cfscript>
    /* Instead of QoQ, limit your Query with queryFilter() */
    filteredQuery = queryFilter( exampleQuery
        ,function(o){ return o.nestedStruct.NID == 12 ;
        }
    ) ;
</cfscript>

Что даст вам переменную filteredQuery, содержащую:

отфильтрованный запрос

Затем вы можете просто обратиться к filteredQuery.nestedArray, чтобы получить массив «Джон, Пол, Джордж и Ринго».

Но вы также хотите отфильтровать массив в nestedArray как 3 элемента. Таким образом, вы можете просто добавить еще одно условие к возврату обратного вызова:

local.filteredQueryForLength = queryFilter( 
    local.exampleQuery2,
    function(o){ return o.nestedStruct.NID == 12 && arrayLen(o.nestedArray) == 3 ; }
) ;

Что затем дает вам пустой объект запроса, поскольку в выбранном вами filteredQuery.nestedArray есть 4 элемента.

Наконец, у queryFilter есть функция-член, которая просто filter(), так что вы можете быть еще короче и использовать это:

local.filteredQueryForLength2 = local.exampleQuery3.filter(
    function(o){ return o.nestedStruct.NID == 12 && o.nestedArray.len() == 3 ; }
) ;

Также помните, что объекты запросов ColdFusion являются объектами Pass-By-Reference, поэтому, если вы сделаете что-либо (например, filter()), которое изменяет объект, он изменит этот базовый объект, поэтому он будет другим, если вы его снова используете. Это также означает, что вам не нужно назначать его переменной. Вы можете просто вызвать queryFilter, а затем сослаться на исходный объект запроса. And another note: when using CF Script syntax (which I much prefer), don't forget that=is assignment and==is comparison. I forgot that initially and all of the records were returning withnestedStruct.NIDas12`. :-/

Последнее примечание: я создал скрипт на https://trycf.com/gist/031a090059a46cd471aa44627fc7ee12/acf2016?theme=monokai. Я добавил один дополнительный элемент в ваш фиктивный запрос, чтобы вы могли видеть, как выглядит ваш возвращаемый объект с несколькими элементами, соответствующими фильтрам.

person Shawn    schedule 03.05.2019