您可以使用结构列值的 属性 值过滤查询查询中的行吗?

Can you filter rows in a Query of Queries using a property value of a struct column value?

如果一个对象,例如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 table list

中的任何 table 不匹配

当不在 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 实现不支持访问列值对象的属性的问题吗?

正如我之前提到的,数据库查询 可以 有一个包含 array/structure-ish 数据的列,但这并不是数据库的真正用途。如您所见,它使查询所需数据变得比应有的困难,并且实际上将数据库视为存储数据的地方。

无论如何,您似乎想通过包含在一列的结构数据中的特定值来过滤查询记录,并且如果另一列数组数据包含一定数量的记录,则还要过滤这些结果。

您不想对此进行查询。它已经是 CF 的一个非常有限的 "query" 方面,应该只在必要时使用。如果您使用的是 ColdFusion 2016+,则可以使用添加的函数:queryFilter()

在 "Given:" 下使用上述设置,您可以使用以下内容:

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

这将为您提供一个变量 filteredQuery,其中包含:

然后你可以只处理 filteredQuery.nestedArray 来得到你的数组 "John, Paul, George and Ringo".

但您还想将 nestedArray 中的数组过滤为 3 个元素。所以你可以在回调中添加另一个条件 return:

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 查询对象是按引用传递的,因此如果您执行任何修改对象的操作(如 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 创建了一个 Fiddle。我向你的模拟查询添加了一个额外的元素,这样你就可以看到你的 return 对象看起来像多个元素匹配过滤器。