CAML 中的 SQL IN 等效项

Posted

技术标签:

【中文标题】CAML 中的 SQL IN 等效项【英文标题】:SQL IN equivalent in CAML 【发布时间】:2010-12-25 20:47:33 【问题描述】:

有没有一种“好”的方法来为 SharePoint 创建一个 CAML 查询来执行类似的操作?

SELECT *
FROM table
WHERE Id IN (3, 12, ...)

还是我陷入了嵌套<Or> 节点的噩梦?


编辑:这是我生成<Or> 节点的解决方案。

/// Simulates a SQL 'Where In' clause in CAML
/// </summary>
/// <param name="columnType">Specifies the data type for the value contained by the field.</param>
/// <returns>Nested 'Or' elements portion of CAML query</returns>
public static string CamlIn<T>(string internalFieldName, string columnType, T[] values)

    XDocument doc = new XDocument();
    XElement prev = null;
    int index = 0;

    while (index < values.Length)
    
        XElement element =
            new XElement("Or",
                new XElement("Eq",
                    new XElement("FieldRef",
                    new XAttribute("Name", internalFieldName)),
                new XElement("Value",
                    new XAttribute("Type", columnType),
                    values[index++].ToString())));

        if (index == values.Length - 1)
        
            element.AddFirst(
                new XElement("Eq",
                    new XElement("FieldRef",
                    new XAttribute("Name", internalFieldName)),
                new XElement("Value",
                    new XAttribute("Type", columnType),
                    values[index++].ToString())));
        

        if (prev != null)
            prev.AddFirst(element);
        else
            doc.Add(element);

        prev = element;
    

    return doc.ToString(SaveOptions.DisableFormatting);

用法:

int[] ids = new int[]  1, 2, 4, 5 ;
string query = string.Format("<Where>0</Where>", CamlIn("SomeColumn", "Number", ids));

输出:

<Where>
    <Or>
        <Or>
            <Or>
                <Eq>
                    <FieldRef Name=\"SomeColumn\" />
                    <Value Type=\"Number\">5</Value>
                </Eq>
                <Eq>
                    <FieldRef Name=\"SomeColumn\" />
                    <Value Type=\"Number\">4</Value>
                </Eq>
            </Or>
            <Eq>
                <FieldRef Name=\"SomeColumn\" />
                <Value Type=\"Number\">2</Value>
            </Eq>
        </Or>
        <Eq>
            <FieldRef Name=\"SomeColumn\" />
            <Value Type=\"Number\">1</Value>
        </Eq>
    </Or>
</Where>

还使使用查找字段的重载变得更容易

/// <summary>
/// Simulates a SQL 'Where In' clause in CAML
/// </summary>
/// <param name="lookupId">Specify whether to use the Lookup column's Id or Value.</param>
/// <returns>Nested 'Or' elements portion of CAML query</returns>
public static string CamlIn<T>(string internalFieldName, bool lookupId, T[] values)

    XDocument doc = new XDocument();
    XElement prev = null;
    int index = 0;

    while (index < values.Length)
    
        XElement element =
            new XElement("Or",
                new XElement("Eq",
                    new XElement("FieldRef",
                        new XAttribute("Name", internalFieldName),
                        lookupId ? new XAttribute("LookupId", "TRUE") : null),
                    new XElement("Value",
                        new XAttribute("Type", "Lookup"),
                        values[index++].ToString())));

        if (index == values.Length - 1)
        
            element.AddFirst(
                new XElement("Eq",
                    new XElement("FieldRef",
                        new XAttribute("Name", internalFieldName),
                        lookupId ? new XAttribute("LookupId", "TRUE") : null),
                    new XElement("Value",
                        new XAttribute("Type", "Lookup"),
                        values[index++].ToString())));
        

        if (prev != null)
            prev.AddFirst(element);
        else
            doc.Add(element);

        prev = element;
    

    if (values.Length == 1)
    
        XElement newRoot = doc.Descendants("Eq").Single();
        doc.RemoveNodes();
        doc.Add(newRoot);
    

    return doc.ToString(SaveOptions.DisableFormatting);

【问题讨论】:

【参考方案1】:

FullTextSqlQuery

可以使用 SQL 语句搜索 MOSS,使用 FullTextSqlQuery 类。我个人没有使用这个类的经验。这些文章可能有用:

http://blogit.create.pt/blogs/ricardocosta/archive/2007/06/15/How-to-use-FullTextSqlQuery-to-search-in-WSS.aspx http://www.dotnetmafia.com/blogs/dotnettipoftheday/archive/2008/03/06/how-to-use-the-moss-enterprise-search-fulltextsqlquery-class.aspx

YACAMLQT

另外,还有YACAMLQT (Yet Another CAML Query Tool) 允许您使用 T-SQL 语法创建 SharePoint CAML 查询。

LINQ to SharePoint

如果您熟悉 LINQ,那么LINQ to SharePoint project 提供了一个使用 LINQ 语法查询 SharePoint 列表的工具。请注意,此工具仍处于 alpha 测试阶段,因此可能无法投入生产。

U2U CAML 查询生成器

如果您使用 CAML 查询,我建议您使用 U2U CAML Query Builder for SharePoint(2003 和 2007)工具来构建您的 CAML 查询。该工具允许您构建查询字符串,并使用点击式界面针对目标列表执行它,如下所示。

(来源:u2u.net)

在上述四种方法中,我可以推荐 U2U CAML 查询生成器,在过去 6 个月中几乎每天都在使用它。它似乎也是 SharePoint 社区中使用最广泛的 CAML 工具。

注意,如果您在代码中构建 CAML 查询,那么我建议您查看 CodePlex 上的 CAML.NET project,它提供了“一组基于 .NET 语言的创建工具动态、可重用的 CAML 查询组件".

【讨论】:

不了解 CAML.NET。将来可能需要使用它。我用 XElements 做了类似的事情来生成必要的&lt;Or&gt;s。【参考方案2】:

不,您需要处理嵌套的OR 标签;这些是supported query instructions on CAML

也许CAML.NET 可以帮助您完成任务。

【讨论】:

【参考方案3】:

对于使用 Sharepoint 2010 的用户,有一个 IN 元素可用:

http://msdn.microsoft.com/en-us/library/ff625761.aspx

这是一个工作示例:

SPQuery locationsQuery = new SPQuery();
locationsQuery.Query = string.Concat("<Where>",
                                       "<In>",
                                         "<FieldRef Name='ID' />",
                                           "<Values>",
                                             "<Value Type='Number'>6</Value>",
                                             "<Value Type='Number'>7</Value>",
                                             "<Value Type='Number'>8</Value>",
                                           "</Values>",
                                       "</In>",
                                     "</Where>");

【讨论】:

【参考方案4】:

我遇到了类似的事情,最终不得不创建一个递归算法来生成嵌套的 OR 结构。这是我的算法

var DynamicQuery = '<Query><Where>DYNAMICSTRING</Where></Query>';
var OneOR = '<Or><Eq><FieldRef Name="IMEI" /><Value Type="Text">SearchValue</Value></Eq>DYNAMICSTRING</Or>';
var TwoOr = '<Or><Eq><FieldRef Name="IMEI" /><Value Type="Text">SearchValue</Value></Eq><Eq><FieldRef Name="IMEI" /><Value Type="Text">SearchValue</Value></Eq></Or>';
var OnlyEq =  '<Eq><FieldRef Name="IMEI" /><Value Type="Text">SearchValue</Value></Eq>';
function generateAdvancedInQuery(x)
    if(x.length == 1)
        return OnlyEq.replace('SearchValue',x[0]);
    else if(x.length == 2)
        return TwoOr.replace('SearchValue',x[0]).replace('SearchValue',x[1]);
    else 
        return OneOR.replace('SearchValue',x[x.length-1]).replace('DYNAMICSTRING',generateAdvancedInQuery(x.splice(0,x.length-1) ) );   


x = ['438753234098792','438753234098793','438753234098794','438753234098795','438753234098796','438753234098797','438753234098798'];

var Caml = DynamicQuery.replace('DYNAMICSTRING',generateAdvancedInQuery(x) )

这会生成 XML caml 查询

<Query>
    <Where>
        <Or>
            <Eq>
                <FieldRef Name="IMEI" />
                <Value Type="Text">438753234098798</Value>
            </Eq>
            <Or>
                <Eq>
                    <FieldRef Name="IMEI" />
                    <Value Type="Text">438753234098797</Value>
                </Eq>
                <Or>
                    <Eq>
                        <FieldRef Name="IMEI" />
                        <Value Type="Text">438753234098796</Value>
                    </Eq>
                    <Or>
                        <Eq>
                            <FieldRef Name="IMEI" />
                            <Value Type="Text">438753234098795</Value>
                        </Eq>
                        <Or>
                            <Eq>
                                <FieldRef Name="IMEI" />
                                <Value Type="Text">438753234098794</Value>
                            </Eq>
                            <Or>
                                <Eq>
                                    <FieldRef Name="IMEI" />
                                    <Value Type="Text">438753234098792</Value>
                                </Eq>
                                <Eq>
                                    <FieldRef Name="IMEI" />
                                    <Value Type="Text">438753234098793</Value>
                                </Eq>
                            </Or>
                        </Or>
                    </Or>
                </Or>
            </Or>
        </Or>
    </Where>
</Query>

【讨论】:

以上是关于CAML 中的 SQL IN 等效项的主要内容,如果未能解决你的问题,请参考以下文章

Sharepoint:限制caml查询中的结果

SQL 语句中的infind_in_setlike的区别

如何使用 SQL 中的“in”和“not in”过滤 Pandas 数据帧

此 SQL 的 Cosmos DB 等效项

SharePoint:如何使用列表中的 CAML 查询获取前 5 条记录

CAML“不在”查询