SharePoint CAML 查询到 T-SQL

发布于 2024-11-04 03:46:14 字数 1370 浏览 0 评论 0原文

我希望将 CAML 查询转换为 T-SQL。对于我的 SharePoint 站点,我还有一个数据仓库 (SQL Server 2005),它托管相同的数据(通过 SPList EventReceivers 填充:ItemAdded、ItemUpdated)。

我参与了一项处理列表增长和显示列表数据的自定义 Web 部件速度的任务。我希望使用数据仓库显示我们的列表内容,然后我们将从工作流程已完成的 SPList 中删除项目。

目前,显示 SPList 内容的自定义 Web 部件的用户可以选择 SPView 以按照他们想要的方式显示内容(即过滤、排序和仅显示必要的列)。我想保留此功能,并希望获取视图的 CAML 查询并将其转换为 T-SQL 以对数据仓库进行查询。

例如

<Query>
  <Where>
    <Or>
      <Eq>
        <FieldRef Name="ContentType" />
        <Value Type="Text">My Content Type</Value>
      </Eq>
      <IsNotNull>
        <FieldRef Name="Description" />
      </IsNotNull>
    </Or>
  </Where>
  <Order>
    <FieldRef Name="Author" />
    <FieldRef Name="AuthoringDate" />
    <FieldRef Name="AssignedTo" Ascending="True" />
  </Order>
  <Group>
    <FieldRef Name="Title" />
  </Group>
</Query>

WHERE ContentType="My Content Type"
OR Description<>null
GROUPBY Title DESC
ORDERBY Author, AuthoringDate, AssignedTo ASC

有谁知道该怎么做?或者有可以解决这个问题的替代建议吗?我找到了多种将 T-SQL 转换为 CAML 查询的解决方案,而不是相反(即 http://yacamlqt. codeplex.com/ -- 这也是我从中检索示例的地方

谢谢!

I was hoping to do convert a CAML query into T-SQL. For my SharePoint site, I also have a data warehouse (SQL Server 2005) which hosts the same data (it is populated through SPList EventReceivers: ItemAdded, ItemUpdated).

I am involved in a task to handle the growth of the lists and the speed of custom webparts that display list data. I am hoping instead to display our list contents using the data warehouse and then we are going to remove items from the SPLists where the workflow has been completed.

Currently, the user of the custom webpart that displays the SPList contents is allowed to select an SPView to display the content in the way they would like (i.e. filtering, sorting and only showing necessary columns). I would like to keep this functionality and was hoping to take the view's CAML query and convert it to T-SQL to query against the data warehouse.

e.g.

<Query>
  <Where>
    <Or>
      <Eq>
        <FieldRef Name="ContentType" />
        <Value Type="Text">My Content Type</Value>
      </Eq>
      <IsNotNull>
        <FieldRef Name="Description" />
      </IsNotNull>
    </Or>
  </Where>
  <Order>
    <FieldRef Name="Author" />
    <FieldRef Name="AuthoringDate" />
    <FieldRef Name="AssignedTo" Ascending="True" />
  </Order>
  <Group>
    <FieldRef Name="Title" />
  </Group>
</Query>

to

WHERE ContentType="My Content Type"
OR Description<>null
GROUPBY Title DESC
ORDERBY Author, AuthoringDate, AssignedTo ASC

Does anyone know how to do this? Or have an alternative suggestion that would solve this issue? I have found multiple solutions for converting T-SQL to CAML query, just not the other way around (i.e. http://yacamlqt.codeplex.com/ -- which is also where I retrieved the example from)

Thanks!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

羅雙樹 2024-11-11 03:46:14

我还希望找到一段代码将 CAML 转换为 SQL,以便构建我自己的 SQL 语句来访问数据。

我的主要项目是构建一个 SharePoint 功能区扩展,以将列表(内部和外部)内容导出到 CSV,并且在外部列表的情况下,能够绕过外部内容类型 (BCS) 中施加的限制 (2000)。

我使用元数据存储和安全存储中的信息来构建连接字符串并直接访问数据库。

当我需要改进代码以包含过滤器时,我最终构建了自己的方法来获取视图查询的“Where”部分并将其转换为类似 SQL 的Where 语句:

输入:

In我的例子是一个 SPView 对象,但它可以很容易地转换为使用字符串。我正在从中提取类似“CAML”的查询。

"<Where>
  <And>
    <Or>
      <Geq>
        <FieldRef Name=\"Microfilm\" />
        <Value Type=\"Text\">10</Value>
      </Geq>
      <Leq>
        <FieldRef Name=\"Microfilm\" />
        <Value Type=\"Text\">50</Value>
      </Leq>
    </Or>
    <BeginsWith>
      <FieldRef Name=\"Title\" />
      <Value Type=\"Text\">Ice</Value>
    </BeginsWith> 
  </And>
</Where>"

输出:

"(Microfilm >= 10 OR Microfilm <= 50) AND Title LIKE 'Ice%'"

以下是方法:

此方法将从视图查询中提取“Where”节点,并
将其传递给一个方法来处理它并返回类似 SQL 的语句。

    private static string ViewQueryToSqlWhere(SPView v)
    {
        string sqlWhere = string.Empty;
        XmlDocument xmlDoc = new XmlDocument();
        XmlNodeList nodeList;

        //Add <Query> around the SPView.Query since a valid XML document requires a single root element.
        //and SPView.Query doesn't.
        xmlDoc.LoadXml("<Query>" + v.Query + "</Query>");

        nodeList = xmlDoc.GetElementsByTagName("Where");

        if (nodeList.Count == 1)
        {
            XmlNode nodeWhere = nodeList[0];

            if (nodeWhere.HasChildNodes) //Should Always be the case
            {
                StringBuilder sb = new StringBuilder();
                bool isSuccess = ProcessWhereNode(nodeWhere, ref sb);
            }
        }

        return sqlWhere;
    }

该方法将调用另一个方法来递归地遍历所有节点以获取视图查询“Where”节点内的值和运算符。它将在“OR”语句周围加上圆括号以保留操作优先级。

    private static bool ProcessWhereNode(XmlNode xmlNode, ref StringBuilder sb)
    {
        bool isSuccess = false;
        Stack<string> operatorStack = new Stack<string>();
        Queue<string> valueQueue = new Queue<string>();
        string previousOp = string.Empty;
        string strOperator = string.Empty;

        try
        {
            //Call a method to iterate "recursively" throught the nodes to get the values and operators.
            if (ProcessRecursiveWhereNode(xmlNode, "", "", ref operatorStack, ref valueQueue))
            {
                while (valueQueue.Count > 0)
                {
                    if (operatorStack.Count > 0)
                    {
                        strOperator = operatorStack.Pop();

                        //Open bracket if it's an OR operator except if the previous one was also an OR.
                        if (strOperator == "OR" && previousOp != "OR")
                            sb.Append("(");
                    }
                    else
                    {
                        strOperator = string.Empty;
                    }

                    sb.Append(valueQueue.Dequeue());

                    //Close bracket if previous OP was an OR, and it's not followed by another one
                    if (previousOp == "OR" && strOperator != "OR")
                        sb.Append(")");

                    if (strOperator != string.Empty)
                    {
                        sb.Append(" " + strOperator + " ");
                    }

                    previousOp = strOperator;
                }
            }
        }
        catch (Exception ex)
        { }

        return isSuccess;
    }

此方法完成了大部分工作来迭代每个节点:

private static bool ProcessRecursiveWhereNode(XmlNode xmlNode, string strOperatorValue, string strOperatorType, ref Stack<string> operatorStack, ref Queue<string> valueQueue)
        {
            bool isSuccess = false;
            string fieldName = string.Empty;
            string value = string.Empty;
            string thisIterationOperatorType = string.Empty;
            string thisIterationOperatorValue = string.Empty;

            try
            {
                XmlNodeList nodeList = xmlNode.ChildNodes;

                //Get Child node - Possible tags {<Or>, <And>, <Eq>, <Neq>, <Gt>, <Lt>, <Geq>, <Leq>, </BeginsWith>, <Contains>, <FieldRef>, <Value>}
                foreach (XmlNode node in nodeList)
                {
                    thisIterationOperatorType = string.Empty;
                    thisIterationOperatorValue = string.Empty;

                    //Check if it's one of these tag: <Or>, <And>, <Eq>, <Neq>, <Gt>, <Lt>, <Geq>, <Leq>, </BeginsWith>, <Contains>
                    thisIterationOperatorValue = GetOperatorString(node.Name, out thisIterationOperatorType);

                    if (thisIterationOperatorType == "statement")
                        operatorStack.Push(thisIterationOperatorValue);

                    //It's one of these tag: <Or>, <And>, <Eq>, <Neq>, <Gt>, <Lt>, <Geq>, <Leq>, </BeginsWith>, <Contains>
                    if (thisIterationOperatorValue != string.Empty)
                    {
                        ProcessRecursiveWhereNode(node, thisIterationOperatorValue, thisIterationOperatorType, ref operatorStack, ref valueQueue);
                    }
                    else //It is probably a <FieldRef> or <Value> tag.
                    {
                        if (node.Name == "FieldRef")
                            fieldName = node.Attributes["Name"].Value.ToString();
                        else if (node.Name == "Value")
                            value = node.LastChild.Value.ToString();
                    }
                }

                if (strOperatorType == "value" && strOperatorValue != string.Empty && fieldName != string.Empty && value != string.Empty)
                {
                    valueQueue.Enqueue(string.Format(strOperatorValue, fieldName, "'" + value + "'"));
                }

                isSuccess = true;
            }
            catch
            {
                isSuccess = false;
                throw;
            }

            return isSuccess;
        }

最后一个方法可能包含在递归方法中,但在我构建代码的第一次迭代中,制作一个单独的方法更有意义,我保持这种方式。

它只是获取有关运算符的一些信息并关联一个运算符字符串,该字符串将用于构造 SQLWhere 语句的各个部分。

static private string GetOperatorString(string tagName, out string operatorType)
{
    string operatorString = string.Empty;

    switch (tagName)
    {
        case "Or":
            operatorString = "OR";
            operatorType = "statement";
            break;
        case "And":
            operatorString = "AND";
            operatorType = "statement";
            break;
        case "Eq":
            operatorString = "{0} = {1}";
            operatorType = "value";
            break;
        case "Neq":
            operatorString = "{0} != {1}";
            operatorType = "value";
            break;
        case "Gt":
            operatorString = "{0} > {1}";
            operatorType = "value";
            break;
        case "Lt":
            operatorString = "{0} < {1}";
            operatorType = "value";
            break;
        case "Geq":
            operatorString = "{0} >= {1}";
            operatorType = "value";
            break;
        case "Leq":
            operatorString = "{0} <= {1}";
            operatorType = "value";
            break;
        case "BeginsWith":
            operatorString = "{0} LIKE '{1}%";
            operatorType = "value";
            break;
        case "Contains":
            operatorString = "{0} LIKE '%{1}%";
            operatorType = "value";
            break;
        default:
            operatorString = string.Empty;
            operatorType = string.Empty;
            break;
    }

    return operatorString;
}

我知道它不是一个完整的转换工具,但它是一个开始,目前它满足我的需要。我希望这会对某人有所帮助并节省他们一些宝贵的时间。

I was also hoping to find a piece of code to convert CAML to SQL in order to build my own SQL Statement to access the data.

My main project is to build a SharePoint ribbon extension to export Lists (Internal and External) content to CSV and in the case of external lists, to be able to bypass the throttling limit (2000) imposed in External Content Types (BCS).

I'm using the information in the metada store and the secure store to build the connection string and access the Database directly.

When I needed to improve my code to include filters, I ended up building my own methods to get the "Where" part of a View Query and convert it to a SQL-Like Where statement:

Input:

In my case it's a SPView object but it can easily be converted to use a string instead. I'm extracting the "CAML" like query from it.

"<Where>
  <And>
    <Or>
      <Geq>
        <FieldRef Name=\"Microfilm\" />
        <Value Type=\"Text\">10</Value>
      </Geq>
      <Leq>
        <FieldRef Name=\"Microfilm\" />
        <Value Type=\"Text\">50</Value>
      </Leq>
    </Or>
    <BeginsWith>
      <FieldRef Name=\"Title\" />
      <Value Type=\"Text\">Ice</Value>
    </BeginsWith> 
  </And>
</Where>"

Ouput:

"(Microfilm >= 10 OR Microfilm <= 50) AND Title LIKE 'Ice%'"

Here are the methods:

This method will extract the "Where" node from a view Query and
pass it to a method to process it and return a SQL like statement.

    private static string ViewQueryToSqlWhere(SPView v)
    {
        string sqlWhere = string.Empty;
        XmlDocument xmlDoc = new XmlDocument();
        XmlNodeList nodeList;

        //Add <Query> around the SPView.Query since a valid XML document requires a single root element.
        //and SPView.Query doesn't.
        xmlDoc.LoadXml("<Query>" + v.Query + "</Query>");

        nodeList = xmlDoc.GetElementsByTagName("Where");

        if (nodeList.Count == 1)
        {
            XmlNode nodeWhere = nodeList[0];

            if (nodeWhere.HasChildNodes) //Should Always be the case
            {
                StringBuilder sb = new StringBuilder();
                bool isSuccess = ProcessWhereNode(nodeWhere, ref sb);
            }
        }

        return sqlWhere;
    }

This method will call another method to recursively go through all the nodes to get the values and operators within the View Query "Where" node. It will put round bracket around "OR" statements to conserve the operation priority.

    private static bool ProcessWhereNode(XmlNode xmlNode, ref StringBuilder sb)
    {
        bool isSuccess = false;
        Stack<string> operatorStack = new Stack<string>();
        Queue<string> valueQueue = new Queue<string>();
        string previousOp = string.Empty;
        string strOperator = string.Empty;

        try
        {
            //Call a method to iterate "recursively" throught the nodes to get the values and operators.
            if (ProcessRecursiveWhereNode(xmlNode, "", "", ref operatorStack, ref valueQueue))
            {
                while (valueQueue.Count > 0)
                {
                    if (operatorStack.Count > 0)
                    {
                        strOperator = operatorStack.Pop();

                        //Open bracket if it's an OR operator except if the previous one was also an OR.
                        if (strOperator == "OR" && previousOp != "OR")
                            sb.Append("(");
                    }
                    else
                    {
                        strOperator = string.Empty;
                    }

                    sb.Append(valueQueue.Dequeue());

                    //Close bracket if previous OP was an OR, and it's not followed by another one
                    if (previousOp == "OR" && strOperator != "OR")
                        sb.Append(")");

                    if (strOperator != string.Empty)
                    {
                        sb.Append(" " + strOperator + " ");
                    }

                    previousOp = strOperator;
                }
            }
        }
        catch (Exception ex)
        { }

        return isSuccess;
    }

This method does most of the work to go throught an iterate each nodes:

private static bool ProcessRecursiveWhereNode(XmlNode xmlNode, string strOperatorValue, string strOperatorType, ref Stack<string> operatorStack, ref Queue<string> valueQueue)
        {
            bool isSuccess = false;
            string fieldName = string.Empty;
            string value = string.Empty;
            string thisIterationOperatorType = string.Empty;
            string thisIterationOperatorValue = string.Empty;

            try
            {
                XmlNodeList nodeList = xmlNode.ChildNodes;

                //Get Child node - Possible tags {<Or>, <And>, <Eq>, <Neq>, <Gt>, <Lt>, <Geq>, <Leq>, </BeginsWith>, <Contains>, <FieldRef>, <Value>}
                foreach (XmlNode node in nodeList)
                {
                    thisIterationOperatorType = string.Empty;
                    thisIterationOperatorValue = string.Empty;

                    //Check if it's one of these tag: <Or>, <And>, <Eq>, <Neq>, <Gt>, <Lt>, <Geq>, <Leq>, </BeginsWith>, <Contains>
                    thisIterationOperatorValue = GetOperatorString(node.Name, out thisIterationOperatorType);

                    if (thisIterationOperatorType == "statement")
                        operatorStack.Push(thisIterationOperatorValue);

                    //It's one of these tag: <Or>, <And>, <Eq>, <Neq>, <Gt>, <Lt>, <Geq>, <Leq>, </BeginsWith>, <Contains>
                    if (thisIterationOperatorValue != string.Empty)
                    {
                        ProcessRecursiveWhereNode(node, thisIterationOperatorValue, thisIterationOperatorType, ref operatorStack, ref valueQueue);
                    }
                    else //It is probably a <FieldRef> or <Value> tag.
                    {
                        if (node.Name == "FieldRef")
                            fieldName = node.Attributes["Name"].Value.ToString();
                        else if (node.Name == "Value")
                            value = node.LastChild.Value.ToString();
                    }
                }

                if (strOperatorType == "value" && strOperatorValue != string.Empty && fieldName != string.Empty && value != string.Empty)
                {
                    valueQueue.Enqueue(string.Format(strOperatorValue, fieldName, "'" + value + "'"));
                }

                isSuccess = true;
            }
            catch
            {
                isSuccess = false;
                throw;
            }

            return isSuccess;
        }

This last methods could probably been included in the recursive one but in my first iteration of building the code it made more sense to make a separate one and I kept it this way.

It simply gets some information on the operators and associates an operator string which will be used to construct the individual pieces of the SQL Where Statement.

static private string GetOperatorString(string tagName, out string operatorType)
{
    string operatorString = string.Empty;

    switch (tagName)
    {
        case "Or":
            operatorString = "OR";
            operatorType = "statement";
            break;
        case "And":
            operatorString = "AND";
            operatorType = "statement";
            break;
        case "Eq":
            operatorString = "{0} = {1}";
            operatorType = "value";
            break;
        case "Neq":
            operatorString = "{0} != {1}";
            operatorType = "value";
            break;
        case "Gt":
            operatorString = "{0} > {1}";
            operatorType = "value";
            break;
        case "Lt":
            operatorString = "{0} < {1}";
            operatorType = "value";
            break;
        case "Geq":
            operatorString = "{0} >= {1}";
            operatorType = "value";
            break;
        case "Leq":
            operatorString = "{0} <= {1}";
            operatorType = "value";
            break;
        case "BeginsWith":
            operatorString = "{0} LIKE '{1}%";
            operatorType = "value";
            break;
        case "Contains":
            operatorString = "{0} LIKE '%{1}%";
            operatorType = "value";
            break;
        default:
            operatorString = string.Empty;
            operatorType = string.Empty;
            break;
    }

    return operatorString;
}

I know it's not a full conversion tool but it's a start and for now it fits my need. I hope this will help someone and save them some valuable time.

余生共白头 2024-11-11 03:46:14

这在技术上不是一个答案,但我觉得有必要。你的做法有点倒退了。在我看来,您真正想做的是使用 sharepoint 作为数据仓库的 UI。如果是这种情况,我会将您的方法切换到本问题范围之外的几个选项之一。

Microsoft 仅通过对象模型、Web 服务或用户界面支持 Sharepoint 中的数据访问。在此之外的任何交互都可能导致大量不受支持的模式,包括损坏的数据、数据锁定、变化的结果集、安全访问等……

听起来真正需要的是 BDC 服务。这将允许您使用数据仓库进行中央存储,并为您提供列表交互的共享点本机功能。

我不确定您使用的是哪个版本,但如果您真的想直接访问数据,SQL 社区中有大量关于直接访问数据的文章。还有一个用于 LINQtoSharePoint 的 codeplex 项目 http://linqtosharepoint.codeplex.com/ 您可以将其用于对象支持您可以使用 LINQ 为您提供 sql 式的功能。

This is not technically an answer but I feel its needed. Your approach is a bit backwards. What it sounds to me like you are really trying to do is use sharepoint as a UI to your data warehouse. If that is the case I would switch your approach to one of several options outside the scope of this question.

Data access in sharepoint is only supported by microsoft through the object model, web services or the user interface. Any interaction outside this can result in a vast range of unsupported modes, anything from corrupt data, data locks, varying result sets, security access, etc...

What it sounds like really need is the BDC services. This would allow you to use the data warehouse for central storage and also provide you with the sharepoint native functionality of the list interactions.

I'm not sure which version you are using but if you REALLY want to hit the data directly there are a large amount of articles in the SQL community about accessing the data directly. There is also a codeplex project for LINQtoSharePoint http://linqtosharepoint.codeplex.com/ You can use this for object support that you can use LINQ to give you sql-esque type functionality.

谎言月老 2024-11-11 03:46:14

我非常简单的类从字符串 sql 转换为 caml ,例如:

CSqlToCAML.TextSqlToCAML(sql);

sql = ....

select id,evid_cislo,nazov,adresa,ulica,vec,datum_zal,datum_odos,ukoncene_dna  
from koresp  
where ((id_typ <= 3 or id_typ = 4) 
 and (datum_zal > datum_odos)) or (id > 21) 
order by nazov desc ,id asc

CAML 输出是 .....

<Query>
<ViewFields>
 <FieldRef Name=" id" /><FieldRef Name="evid_cislo" /><FieldRef Name="nazov" />
 <FieldRef Name="adresa" /><FieldRef Name="ulica" />
 <FieldRef Name="vec" /><FieldRef Name="datum_zal" />
 <FieldRef Name="datum_odos" /><FieldRef Name="ukoncene_dna  " />
</ViewFields>
<Where>
 <Or>
  <Leq><FieldRef Name="id_typ" /><Value Type="Text">3</Value></Leq>
  <Eq><FieldRef Name="id_typ" /><Value Type="Text">4</Value></Eq>
 </Or>
 <Or>
  <Gt><FieldRef Name="datum_zal" /><Value Type="Text">datum_odos</Value></Gt>
 </Or>
 <Or>
  <Gt><FieldRef Name="id" /><Value Type="Text">21</Value></Gt>
 </Or>
</Where>
<OrderBy>
 <FieldRef Name="nazov" Ascending="FALSE" />
 <FieldRef Name="id" Ascending="TRUE" />
</OrderBy>
</Query>

Class src:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;


namespace SPASMXServices.ISAPI
{
public static class CSqlToCAML
{


    public static string TextSqlToCAML(string query)
    {
        string ret = "";
        try
        {
            string[] grpsExpr = query.ToLower().Split(new string[] { "select","from","where","order by","having" }, StringSplitOptions.RemoveEmptyEntries);
            ret += TextSqlToCAML(getValueStrArr(grpsExpr, 0), 
                                 getValueStrArr(grpsExpr, 1), 
                                 getValueStrArr(grpsExpr, 2), 
                                 getValueStrArr(grpsExpr, 3), 
                                 getValueStrArr(grpsExpr, 4)
                                );
        }
        catch (Exception ex)
        {
            Log("CSqlToCAML.TextSqlToCAML() error: " + ex.Message);
        }
        return ret;
    }

    public static string TextSqlToCAML(string select, string from, string where, string orderby, string having)
    {
        string ret = "<Query>";
        try
        {
            ret += sqltocamlSelect(select);
            ret += sqltocamlWhere(where);
            ret += sqltocamlOrderBy(orderby);
        }
        catch (Exception ex)
        {
            Log("CSqlToCAML.TextSqlToCAML() error: " + ex.Message);
        }
        return ret + "</Query>";
    }


    private static string getValueStrArr(string[] strs, int index)
    {
        try
        {
            return strs[index];
        }
        catch
        {
            return "";
        }
    }

    private static string sqltocamlOrderBy(string _orderby)
    {
        string ret = "";
        try
        {
            ret += "<OrderBy>\n";
            string[] grpsExpr = _orderby.ToLower().Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries);
            foreach (string expr in grpsExpr)
            {
                string val = expr.ToLower();
                string ascc = val.ToLower().Contains("asc") ? "TRUE" : val.ToLower().Contains("desc") ? "FALSE" : "TRUE";
                val = val.Replace("asc", "");
                val = val.Replace("desc", "");
                val = val.Trim();
                ret += string.Format("<FieldRef Name=\"{0}\" Ascending=\"{1}\" />\n", val,ascc).Trim();
            }
            ret += "</OrderBy>\n";
        }
        catch (Exception ex)
        {
            Log("CSqlToCAML.sqltocamlSelect() error: " + ex.Message);
        }
        return ret;
    }

    private static string sqltocamlSelect(string _select)
    {
        string ret = "";
        try
        {
            ret += "<ViewFields>\n";
            string[] grpsExpr = _select.ToLower().Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries);
            foreach (string expr in grpsExpr)
            {
                ret += string.Format("<FieldRef Name=\"{0}\" />\n", expr).Trim(); 
            }
            ret += "</ViewFields>\n";
        }
        catch (Exception ex)
        {
            Log("CSqlToCAML.sqltocamlSelect() error: " + ex.Message);
        }
        return ret;
    }

    private static string sqltocamlWhere(string _where)
    {
        string ret = "", retAnd = "", retOr = "";
        try
        {
            /*
            •Eq = equal to  
            •Neq = not equal to 
            •BeginsWith = begins with 
            •Contains = contains 
            •Lt = less than 
            •Leq = less than or equal to
            •Gt = greater than 
            •Geq = greater than or equal to 
            •IsNull = is null 
            •IsNotNull = is not null
            */

            // "(id_typ = 3 or id_typ = 4) and (datum_zal > datum_odos) "
            ret += "<Where>\n";
            string[] grpsExpr = _where.ToLower().Split(new string[] { "(", ")"}, StringSplitOptions.RemoveEmptyEntries);
            foreach (string expr in grpsExpr)
            {

                if (expr.Contains("and"))
                {
                    retAnd = "";
                    foreach (string exp in expr.Split(new string[] { "and" }, StringSplitOptions.RemoveEmptyEntries))
                    {
                        retAnd += expStr(exp);
                    }
                    if (retAnd.Length > 0)
                    {
                        ret += "<And>\n";
                        ret += retAnd;
                        ret += "</And>\n";
                    }
                }

                if (expr.Contains("or") != null)
                {
                    retOr = "";
                    foreach (string exp in expr.Split(new string[] { "or" }, StringSplitOptions.RemoveEmptyEntries))
                    {
                        retOr += expStr(exp);
                    }
                    if (retOr.Length > 0)
                    {
                        ret += "<Or>\n";
                        ret += retOr;
                        ret += "</Or>\n";
                    }
                }
            }
            ret += "</Where>\n";
        }
        catch (Exception ex)
        {
            Log("CSqlToCAML.sqltocamlWhere() error: " + ex.Message);
        }
        return ret;
    }

    private static string expStr(string exp)
    {
        string ret = "";
        ret += propExp(exp, "=");
        ret += propExp(exp, "<>");
        ret += propExp(exp, "<");
        ret += propExp(exp, ">");
        ret += propExp(exp, "<=");
        ret += propExp(exp, ">=");
        ret += propExp(exp, "is null");
        ret += propExp(exp, "is not null");
        ret += propExp(exp, "in");
        ret += propExp(exp, "like");
        ret += propExp(exp, "between");
        return ret;
    }


    private static string propExp(string sExp, string op)
    {
        string ret = "", _op = "";
        try
        {
            if (!sExp.Contains(op))
                return "";
            sExp = sExp.Replace("'", " ");
            sExp = sExp.Replace("   "," ");
            sExp = sExp.Replace("  ", " ");                
            string[] _ops = sExp.Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries);
            string[] _opx = sExp.Split(new string[] { op }, StringSplitOptions.RemoveEmptyEntries);

            if (_ops[1] != op)
                return "";

            string name, value;
            name = sExp.Split(new string[] { op }, StringSplitOptions.RemoveEmptyEntries)[0];
            value = sExp.Split(new string[] { op }, StringSplitOptions.RemoveEmptyEntries)[1];
            value = value.Trim();
            name = name.Trim();

            while(true)
            {

                if (sExp.Contains(op) && op == "<=")
                {
                    _op = "Leq";
                    break;
                }

                if (sExp.Contains(op) && op == ">=")
                {
                    _op = "Geq";
                    break;
                }

                if (sExp.Contains(op) && op == "=")
                {
                    _op = "Eq";
                    break;
                }

                if (sExp.Contains(op) && op == "<>")
                {
                    _op = "Eq";
                    break;
                }

                if (sExp.Contains(op) && op == "<>" && sExp.Contains("null"))
                {
                    _op = "IsNotNull";
                    break;
                }

                if (sExp.Contains(op) && op == "is not null")
                {
                    _op = "IsNotNull";
                    break;
                }

                if (sExp.Contains(op) && op == "is null")
                {
                    _op = "IsNull";
                    break;
                }

                if (sExp.Contains(op) && op == "<")
                {
                    _op = "Lt";
                    break;
                }

                if (sExp.Contains(op) && op == ">")
                {
                    _op = "Gt";
                    break;
                }
                break;
            }
            if (!string.IsNullOrEmpty(_op) && !string.IsNullOrEmpty(name))
                ret += string.Format("<{0}><FieldRef Name=\"{1}\" /><Value Type=\"Text\">{2}</Value></{0}>\n", _op, name, value);
        }
        catch (Exception ex)
        {
            Log("CSqlToCAML.propExp(" + sExp + ") error: " + ex.Message);
        }
        return ret;
    }


    private static void Log(string text)
    {
        //MessageBox.Show(text);
        LOG += string.Format("[{0} - {1};\n]", DateTime.Now, text);
    }


    public static string LOG;
}
}

(bob.)

My very simple class convert from string sql to caml , for example:

CSqlToCAML.TextSqlToCAML(sql);

sql = ....

select id,evid_cislo,nazov,adresa,ulica,vec,datum_zal,datum_odos,ukoncene_dna  
from koresp  
where ((id_typ <= 3 or id_typ = 4) 
 and (datum_zal > datum_odos)) or (id > 21) 
order by nazov desc ,id asc

CAML output is .....

<Query>
<ViewFields>
 <FieldRef Name=" id" /><FieldRef Name="evid_cislo" /><FieldRef Name="nazov" />
 <FieldRef Name="adresa" /><FieldRef Name="ulica" />
 <FieldRef Name="vec" /><FieldRef Name="datum_zal" />
 <FieldRef Name="datum_odos" /><FieldRef Name="ukoncene_dna  " />
</ViewFields>
<Where>
 <Or>
  <Leq><FieldRef Name="id_typ" /><Value Type="Text">3</Value></Leq>
  <Eq><FieldRef Name="id_typ" /><Value Type="Text">4</Value></Eq>
 </Or>
 <Or>
  <Gt><FieldRef Name="datum_zal" /><Value Type="Text">datum_odos</Value></Gt>
 </Or>
 <Or>
  <Gt><FieldRef Name="id" /><Value Type="Text">21</Value></Gt>
 </Or>
</Where>
<OrderBy>
 <FieldRef Name="nazov" Ascending="FALSE" />
 <FieldRef Name="id" Ascending="TRUE" />
</OrderBy>
</Query>

Class src:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;


namespace SPASMXServices.ISAPI
{
public static class CSqlToCAML
{


    public static string TextSqlToCAML(string query)
    {
        string ret = "";
        try
        {
            string[] grpsExpr = query.ToLower().Split(new string[] { "select","from","where","order by","having" }, StringSplitOptions.RemoveEmptyEntries);
            ret += TextSqlToCAML(getValueStrArr(grpsExpr, 0), 
                                 getValueStrArr(grpsExpr, 1), 
                                 getValueStrArr(grpsExpr, 2), 
                                 getValueStrArr(grpsExpr, 3), 
                                 getValueStrArr(grpsExpr, 4)
                                );
        }
        catch (Exception ex)
        {
            Log("CSqlToCAML.TextSqlToCAML() error: " + ex.Message);
        }
        return ret;
    }

    public static string TextSqlToCAML(string select, string from, string where, string orderby, string having)
    {
        string ret = "<Query>";
        try
        {
            ret += sqltocamlSelect(select);
            ret += sqltocamlWhere(where);
            ret += sqltocamlOrderBy(orderby);
        }
        catch (Exception ex)
        {
            Log("CSqlToCAML.TextSqlToCAML() error: " + ex.Message);
        }
        return ret + "</Query>";
    }


    private static string getValueStrArr(string[] strs, int index)
    {
        try
        {
            return strs[index];
        }
        catch
        {
            return "";
        }
    }

    private static string sqltocamlOrderBy(string _orderby)
    {
        string ret = "";
        try
        {
            ret += "<OrderBy>\n";
            string[] grpsExpr = _orderby.ToLower().Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries);
            foreach (string expr in grpsExpr)
            {
                string val = expr.ToLower();
                string ascc = val.ToLower().Contains("asc") ? "TRUE" : val.ToLower().Contains("desc") ? "FALSE" : "TRUE";
                val = val.Replace("asc", "");
                val = val.Replace("desc", "");
                val = val.Trim();
                ret += string.Format("<FieldRef Name=\"{0}\" Ascending=\"{1}\" />\n", val,ascc).Trim();
            }
            ret += "</OrderBy>\n";
        }
        catch (Exception ex)
        {
            Log("CSqlToCAML.sqltocamlSelect() error: " + ex.Message);
        }
        return ret;
    }

    private static string sqltocamlSelect(string _select)
    {
        string ret = "";
        try
        {
            ret += "<ViewFields>\n";
            string[] grpsExpr = _select.ToLower().Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries);
            foreach (string expr in grpsExpr)
            {
                ret += string.Format("<FieldRef Name=\"{0}\" />\n", expr).Trim(); 
            }
            ret += "</ViewFields>\n";
        }
        catch (Exception ex)
        {
            Log("CSqlToCAML.sqltocamlSelect() error: " + ex.Message);
        }
        return ret;
    }

    private static string sqltocamlWhere(string _where)
    {
        string ret = "", retAnd = "", retOr = "";
        try
        {
            /*
            •Eq = equal to  
            •Neq = not equal to 
            •BeginsWith = begins with 
            •Contains = contains 
            •Lt = less than 
            •Leq = less than or equal to
            •Gt = greater than 
            •Geq = greater than or equal to 
            •IsNull = is null 
            •IsNotNull = is not null
            */

            // "(id_typ = 3 or id_typ = 4) and (datum_zal > datum_odos) "
            ret += "<Where>\n";
            string[] grpsExpr = _where.ToLower().Split(new string[] { "(", ")"}, StringSplitOptions.RemoveEmptyEntries);
            foreach (string expr in grpsExpr)
            {

                if (expr.Contains("and"))
                {
                    retAnd = "";
                    foreach (string exp in expr.Split(new string[] { "and" }, StringSplitOptions.RemoveEmptyEntries))
                    {
                        retAnd += expStr(exp);
                    }
                    if (retAnd.Length > 0)
                    {
                        ret += "<And>\n";
                        ret += retAnd;
                        ret += "</And>\n";
                    }
                }

                if (expr.Contains("or") != null)
                {
                    retOr = "";
                    foreach (string exp in expr.Split(new string[] { "or" }, StringSplitOptions.RemoveEmptyEntries))
                    {
                        retOr += expStr(exp);
                    }
                    if (retOr.Length > 0)
                    {
                        ret += "<Or>\n";
                        ret += retOr;
                        ret += "</Or>\n";
                    }
                }
            }
            ret += "</Where>\n";
        }
        catch (Exception ex)
        {
            Log("CSqlToCAML.sqltocamlWhere() error: " + ex.Message);
        }
        return ret;
    }

    private static string expStr(string exp)
    {
        string ret = "";
        ret += propExp(exp, "=");
        ret += propExp(exp, "<>");
        ret += propExp(exp, "<");
        ret += propExp(exp, ">");
        ret += propExp(exp, "<=");
        ret += propExp(exp, ">=");
        ret += propExp(exp, "is null");
        ret += propExp(exp, "is not null");
        ret += propExp(exp, "in");
        ret += propExp(exp, "like");
        ret += propExp(exp, "between");
        return ret;
    }


    private static string propExp(string sExp, string op)
    {
        string ret = "", _op = "";
        try
        {
            if (!sExp.Contains(op))
                return "";
            sExp = sExp.Replace("'", " ");
            sExp = sExp.Replace("   "," ");
            sExp = sExp.Replace("  ", " ");                
            string[] _ops = sExp.Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries);
            string[] _opx = sExp.Split(new string[] { op }, StringSplitOptions.RemoveEmptyEntries);

            if (_ops[1] != op)
                return "";

            string name, value;
            name = sExp.Split(new string[] { op }, StringSplitOptions.RemoveEmptyEntries)[0];
            value = sExp.Split(new string[] { op }, StringSplitOptions.RemoveEmptyEntries)[1];
            value = value.Trim();
            name = name.Trim();

            while(true)
            {

                if (sExp.Contains(op) && op == "<=")
                {
                    _op = "Leq";
                    break;
                }

                if (sExp.Contains(op) && op == ">=")
                {
                    _op = "Geq";
                    break;
                }

                if (sExp.Contains(op) && op == "=")
                {
                    _op = "Eq";
                    break;
                }

                if (sExp.Contains(op) && op == "<>")
                {
                    _op = "Eq";
                    break;
                }

                if (sExp.Contains(op) && op == "<>" && sExp.Contains("null"))
                {
                    _op = "IsNotNull";
                    break;
                }

                if (sExp.Contains(op) && op == "is not null")
                {
                    _op = "IsNotNull";
                    break;
                }

                if (sExp.Contains(op) && op == "is null")
                {
                    _op = "IsNull";
                    break;
                }

                if (sExp.Contains(op) && op == "<")
                {
                    _op = "Lt";
                    break;
                }

                if (sExp.Contains(op) && op == ">")
                {
                    _op = "Gt";
                    break;
                }
                break;
            }
            if (!string.IsNullOrEmpty(_op) && !string.IsNullOrEmpty(name))
                ret += string.Format("<{0}><FieldRef Name=\"{1}\" /><Value Type=\"Text\">{2}</Value></{0}>\n", _op, name, value);
        }
        catch (Exception ex)
        {
            Log("CSqlToCAML.propExp(" + sExp + ") error: " + ex.Message);
        }
        return ret;
    }


    private static void Log(string text)
    {
        //MessageBox.Show(text);
        LOG += string.Format("[{0} - {1};\n]", DateTime.Now, text);
    }


    public static string LOG;
}
}

(bob.)

浮萍、无处依 2024-11-11 03:46:14

如果您使用某种用于 SharePoint 的 ado.net 连接器,则可以查看 http:// /www.bendsoft.com/net-sharepoint-connector/

它使您能够与 SharePoint 列表进行对话,就像它们在普通 sql 表中一样

在示例中插入一些数据

public void SharePointConnectionExample1()
{
    using (SharePointConnection connection = new SharePointConnection(@"
                Server=mysharepointserver.com;
                Database=mysite/subsite
                User=spuser;
                Password=******;
                Authentication=Ntlm;
                TimeOut=10;
                StrictMode=True;
                RecursiveMode=RecursiveAll;
                DefaultLimit=1000;
                CacheTimeout=5"))
    {
        connection.Open();
        using (SharePointCommand command = new SharePointCommand("UPDATE `mytable` SET `mycolumn` = 'hello world'", connection))
        {
            command.ExecuteNonQuery();
        }
    }
}

或将列表数据选择到 DataTable

string query = "SELECT * FROM list";
conn = new SharePointConnection(connectionString);
SharePointDataAdapter adapter = new SharePointDataAdapter(query, conn);

DataTable dt = new DataTable();
adapter.Fill(dt);

或使用助手填充 DataGrid 的方法

string query = "Select * from mylist.viewname";
DataGrid dataGrid = new DataGrid();
dataGrid.DataSource = Camelot.SharePointConnector.Data.Helper.ExecuteDataTable(query, connectionString);
dataGrid.DataBind();
Controls.Add(dataGrid);

以下是一个网络广播,说明如何为 SharePoint 构建简单的查询浏览器,http:// www.youtube.com/watch?v=HzKVTZEsL4Y

希望有帮助!

It's possible if you use some sort of ado.net connector for SharePoint, have a look at http://www.bendsoft.com/net-sharepoint-connector/

It enables you to talk to SharePoint lists as if they where ordinary sql tables

In example to insert some data

public void SharePointConnectionExample1()
{
    using (SharePointConnection connection = new SharePointConnection(@"
                Server=mysharepointserver.com;
                Database=mysite/subsite
                User=spuser;
                Password=******;
                Authentication=Ntlm;
                TimeOut=10;
                StrictMode=True;
                RecursiveMode=RecursiveAll;
                DefaultLimit=1000;
                CacheTimeout=5"))
    {
        connection.Open();
        using (SharePointCommand command = new SharePointCommand("UPDATE `mytable` SET `mycolumn` = 'hello world'", connection))
        {
            command.ExecuteNonQuery();
        }
    }
}

Or to select list data to a DataTable

string query = "SELECT * FROM list";
conn = new SharePointConnection(connectionString);
SharePointDataAdapter adapter = new SharePointDataAdapter(query, conn);

DataTable dt = new DataTable();
adapter.Fill(dt);

Or using a helper method to fill a DataGrid

string query = "Select * from mylist.viewname";
DataGrid dataGrid = new DataGrid();
dataGrid.DataSource = Camelot.SharePointConnector.Data.Helper.ExecuteDataTable(query, connectionString);
dataGrid.DataBind();
Controls.Add(dataGrid);

Here is a webcast illustrating how to build a simple querybrowser for SharePoint, http://www.youtube.com/watch?v=HzKVTZEsL4Y

Hope it helps!

傾旎 2024-11-11 03:46:14

Microsoft 通过以下方式支持 SharePoint 列表数据访问:
1. SharePoint 对象模型 – SPSite 和 SPWeb
2. 列出 Web 服务。访问路径为 http://Your_Site/_vti_bin/lists.asmx

任意添加/更新/删除/选择SharePoint 列表上的操作是使用上述两种方法中的任何一种通过非托管 COM 组件完成的。该COM负责建立与Content DB的连接;在表和数据检索上应用数据锁。该 COM 组件有自己的逻辑/机制来在内容 DB 表上应用数据锁定,并且 Sharepoint 开发人员无法控制数据锁定机制。如果直接在内容数据库表上执行 T-SQL 语句(添加/更新/删除/选择),则此内置逻辑可能会中断,并可能导致未知结果或错误。 Microsoft 不支持在 Content DB 表上直接执行 T-SQL 语句。

Microsoft supports SharePoint List data access through:
1. SharePoint Object Model – SPSite and SPWeb
2. Lists web service. Path to access is http://Your_Site/_vti_bin/lists.asmx

Any Add/Update/Delete/Select operations on the SharePoint List is done using any of the above 2 methods goes through the unmanaged COM component. This COM is responsible for establishing the connection with Content DB; applying Data Locks on the Tables and data retrieval. This COM component has its own Logic/Mechanism to apply Data Lock on the Content DB tables and Sharepoint developer does not have control over the Data Lock mechanism. If T-SQL statements (Add/Update/Delete/Select) are executed directly on the Content DB tables, this In-Build logic may break and can be resulted into unknown results or errors. Microsoft does not support direct T-SQL statement execution on Content DB tables.

滿滿的愛 2024-11-11 03:46:14

我已经使用以下 CAML 检查了 Francis 发布的代码:

<Where>
    <Or>
        <And>
            <Neq><FieldRef Name="F1" /><Value Type="Text">Yes</Value></Neq>
            <Neq><FieldRef Name="F2" /><Value Type="Text">Yes</Value></Neq>
        </And>
        <Eq><FieldRef Name="F3" /><Value Type="Text">Yes</Value></Eq>
    </Or>
</Where>

它不起作用...在这种情况下,结果将是: F1<>'Yes' AND ( F2<>'Yes' OR F3 ='是')。

我在以下方法中做了一些修复:

private bool ProcessWhereNode(XmlNode xmlNode, ref StringBuilder sb) {
        bool isSuccess = false;
        Stack<string> operatorStack = new Stack<string>();
        Queue<string> valueQueue = new Queue<string>();
        string previousOp = string.Empty;
        string strOperator = string.Empty;

        try {
            //Call a method to iterate "recursively" throught the nodes to get the values and operators.
            if (ProcessRecursiveWhereNode(xmlNode, "", "", ref operatorStack, ref valueQueue)) {

                // For each operator adding parenthesis before starting 
                StringBuilder sbTmp = new StringBuilder();
                operatorStack.ToList().ForEach(x => sbTmp.Append("("));
                sb.Append(sbTmp.ToString());

                while (valueQueue.Count > 0) {
                    if (operatorStack.Count > 0) {
                        strOperator = operatorStack.Pop();

                    } else {
                        strOperator = string.Empty;
                    }

                    sb.Append(valueQueue.Dequeue());

                    // After each logical operation closing parenthesis 
                    if (previousOp != string.Empty)
                        sb.Append(")");

                    if (strOperator != string.Empty) 
                        sb.Append(" " + strOperator + " ");

                    previousOp = strOperator;
                }
            }
            isSuccess = true;
        } catch (Exception) {
            isSuccess = false;
        }

        return isSuccess;
    }

这会将括号内的夫妇分组......仅此而已

i have checked the code posted by Francis with the following CAML:

<Where>
    <Or>
        <And>
            <Neq><FieldRef Name="F1" /><Value Type="Text">Yes</Value></Neq>
            <Neq><FieldRef Name="F2" /><Value Type="Text">Yes</Value></Neq>
        </And>
        <Eq><FieldRef Name="F3" /><Value Type="Text">Yes</Value></Eq>
    </Or>
</Where>

And it doesn't work... the result, in this case, will be: F1<>'Yes' AND ( F2<>'Yes' OR F3='Yes' ).

I made some fixes inside the following method:

private bool ProcessWhereNode(XmlNode xmlNode, ref StringBuilder sb) {
        bool isSuccess = false;
        Stack<string> operatorStack = new Stack<string>();
        Queue<string> valueQueue = new Queue<string>();
        string previousOp = string.Empty;
        string strOperator = string.Empty;

        try {
            //Call a method to iterate "recursively" throught the nodes to get the values and operators.
            if (ProcessRecursiveWhereNode(xmlNode, "", "", ref operatorStack, ref valueQueue)) {

                // For each operator adding parenthesis before starting 
                StringBuilder sbTmp = new StringBuilder();
                operatorStack.ToList().ForEach(x => sbTmp.Append("("));
                sb.Append(sbTmp.ToString());

                while (valueQueue.Count > 0) {
                    if (operatorStack.Count > 0) {
                        strOperator = operatorStack.Pop();

                    } else {
                        strOperator = string.Empty;
                    }

                    sb.Append(valueQueue.Dequeue());

                    // After each logical operation closing parenthesis 
                    if (previousOp != string.Empty)
                        sb.Append(")");

                    if (strOperator != string.Empty) 
                        sb.Append(" " + strOperator + " ");

                    previousOp = strOperator;
                }
            }
            isSuccess = true;
        } catch (Exception) {
            isSuccess = false;
        }

        return isSuccess;
    }

This will group the couple inside the parentheses ... and that's all

彡翼 2024-11-11 03:46:14

感谢您的帮助,我也需要它,您的代码很好,但我改进了一点:

  • operator is null 和 isnotnull 没有处理
  • 关于使用 like 运算符转义的小错误,

请小心代码不会转义列名称(您必须根据您的数据库引擎来执行此操作)

这里是静态类中的代码:

//http://stackoverflow.com/questions/5834700/sharepoint-caml-query-to-t-sql
public static class CAMLtoSQL
{
    public static string ViewQueryToSqlWhere(string query)
    {
        string sqlWhere = string.Empty;
        XmlDocument xmlDoc = new XmlDocument();
        XmlNodeList nodeList;

        //Add <Query> around the SPView.Query since a valid XML document requires a single root element.
        //and SPView.Query doesn't.
        xmlDoc.LoadXml("<Query>" + query + "</Query>");

        nodeList = xmlDoc.GetElementsByTagName("Where");

        if (nodeList.Count == 1)
        {
            XmlNode nodeWhere = nodeList[0];

            if (nodeWhere.HasChildNodes) //Should Always be the case
            {
                StringBuilder sb = new StringBuilder();
                bool isSuccess = ProcessWhereNode(nodeWhere, ref sb);
                sqlWhere = sb.ToString();
            }
        }

        return sqlWhere;
    }
    private static bool ProcessWhereNode(XmlNode xmlNode, ref StringBuilder sb)
    {
        bool isSuccess = false;
        Stack<string> operatorStack = new Stack<string>();
        Queue<string> valueQueue = new Queue<string>();
        string previousOp = string.Empty;
        string strOperator = string.Empty;

        try
        {
            //Call a method to iterate "recursively" throught the nodes to get the values and operators.
            if (ProcessRecursiveWhereNode(xmlNode, "", "", ref operatorStack, ref valueQueue))
            {

                // For each operator adding parenthesis before starting 
                StringBuilder sbTmp = new StringBuilder();
                operatorStack.ToList().ForEach(x => sbTmp.Append("("));
                sb.Append(sbTmp.ToString());

                while (valueQueue.Count > 0)
                {
                    if (operatorStack.Count > 0)
                    {
                        strOperator = operatorStack.Pop();

                    }
                    else
                    {
                        strOperator = string.Empty;
                    }

                    sb.Append(valueQueue.Dequeue());

                    // After each logical operation closing parenthesis 
                    if (previousOp != string.Empty)
                        sb.Append(")");

                    if (strOperator != string.Empty)
                        sb.Append(" " + strOperator + " ");

                    previousOp = strOperator;
                }
            }
            isSuccess = true;
        }
        catch (Exception)
        {
            isSuccess = false;
        }

        return isSuccess;
    }

    private static bool ProcessRecursiveWhereNode(XmlNode xmlNode, string strOperatorValue, string strOperatorType, ref Stack<string> operatorStack, ref Queue<string> valueQueue)
    {
        bool isSuccess = false;
        string fieldName = string.Empty;
        string value = string.Empty;
        string thisIterationOperatorType = string.Empty;
        string thisIterationOperatorValue = string.Empty;

        try
        {
            XmlNodeList nodeList = xmlNode.ChildNodes;

            //Get Child node - Possible tags {<Or>, <And>, <Eq>, <Neq>, <Gt>, <Lt>, <Geq>, <Leq>, </BeginsWith>, <Contains>, <IsNotNull>, <IsNull>, <FieldRef>, <Value>}
            foreach (XmlNode node in nodeList)
            {
                thisIterationOperatorType = string.Empty;
                thisIterationOperatorValue = string.Empty;

                //Check if it's one of these tag: <Or>, <And>, <Eq>, <Neq>, <Gt>, <Lt>, <Geq>, <Leq>, </BeginsWith>, <Contains>, <IsNotNull>, <IsNull>
                thisIterationOperatorValue = GetOperatorString(node.Name, out thisIterationOperatorType);

                if (thisIterationOperatorType == "statement")
                    operatorStack.Push(thisIterationOperatorValue);

                //It's one of these tag: <Or>, <And>, <Eq>, <Neq>, <Gt>, <Lt>, <Geq>, <Leq>, </BeginsWith>, <Contains>, <IsNotNull>, <IsNull>
                if (thisIterationOperatorValue != string.Empty)
                {
                    ProcessRecursiveWhereNode(node, thisIterationOperatorValue, thisIterationOperatorType, ref operatorStack, ref valueQueue);
                }
                else if (strOperatorType != "statement") //It is probably a <FieldRef> or <Value> tag.
                {
                    if (node.Name == "FieldRef")
                        fieldName = node.Attributes["Name"].Value.ToString();
                    else if (node.Name == "Value")
                        value = node.LastChild.Value.ToString();
                }
            }

            if ((strOperatorType == "value" && strOperatorValue != string.Empty && fieldName != string.Empty && value != string.Empty)
                ||
                (strOperatorType == "is" && strOperatorValue != string.Empty && fieldName != string.Empty))
            {
                // if contains a like we don't add the '
                if (strOperatorValue.Contains("LIKE"))
                    valueQueue.Enqueue(string.Format(strOperatorValue, fieldName, value));
                else
                    valueQueue.Enqueue(string.Format(strOperatorValue, fieldName, "'" + value + "'"));
            }

            isSuccess = true;
        }
        catch
        {
            isSuccess = false;
            throw;
        }

        return isSuccess;
    }

    private static string GetOperatorString(string tagName, out string operatorType)
    {
        string operatorString = string.Empty;

        switch (tagName)
        {
            case "Or":
                operatorString = "OR";
                operatorType = "statement";
                break;
            case "And":
                operatorString = "AND";
                operatorType = "statement";
                break;
            case "Eq":
                operatorString = "{0} = {1}";
                operatorType = "value";
                break;
            case "Neq":
                operatorString = "{0} != {1}";
                operatorType = "value";
                break;
            case "Gt":
                operatorString = "{0} > {1}";
                operatorType = "value";
                break;
            case "Lt":
                operatorString = "{0} < {1}";
                operatorType = "value";
                break;
            case "Geq":
                operatorString = "{0} >= {1}";
                operatorType = "value";
                break;
            case "Leq":
                operatorString = "{0} <= {1}";
                operatorType = "value";
                break;
            case "BeginsWith":
                operatorString = "{0} LIKE '{1}%'";
                operatorType = "value";
                break;
            case "Contains":
                operatorString = "{0} LIKE '%{1}%'";
                operatorType = "value";
                break;
            case "IsNotNull":
                operatorString = "{0} IS NOT NULL";
                operatorType = "is";
                break;
            case "IsNull":
                operatorString = "{0} IS NULL";
                operatorType = "is";
                break;

            default:
                operatorString = string.Empty;
                operatorType = string.Empty;
                break;
        }

        return operatorString;
    }
}

thanks for your help, i need that too, your code was good but i improve it a little :

  • operator is null and isnotnull wasn't handle
  • a little bug about escaping with like operator

be careful the code doesn't escape the column name (you have to do it depending of your database engine)

here is the code in a static class:

//http://stackoverflow.com/questions/5834700/sharepoint-caml-query-to-t-sql
public static class CAMLtoSQL
{
    public static string ViewQueryToSqlWhere(string query)
    {
        string sqlWhere = string.Empty;
        XmlDocument xmlDoc = new XmlDocument();
        XmlNodeList nodeList;

        //Add <Query> around the SPView.Query since a valid XML document requires a single root element.
        //and SPView.Query doesn't.
        xmlDoc.LoadXml("<Query>" + query + "</Query>");

        nodeList = xmlDoc.GetElementsByTagName("Where");

        if (nodeList.Count == 1)
        {
            XmlNode nodeWhere = nodeList[0];

            if (nodeWhere.HasChildNodes) //Should Always be the case
            {
                StringBuilder sb = new StringBuilder();
                bool isSuccess = ProcessWhereNode(nodeWhere, ref sb);
                sqlWhere = sb.ToString();
            }
        }

        return sqlWhere;
    }
    private static bool ProcessWhereNode(XmlNode xmlNode, ref StringBuilder sb)
    {
        bool isSuccess = false;
        Stack<string> operatorStack = new Stack<string>();
        Queue<string> valueQueue = new Queue<string>();
        string previousOp = string.Empty;
        string strOperator = string.Empty;

        try
        {
            //Call a method to iterate "recursively" throught the nodes to get the values and operators.
            if (ProcessRecursiveWhereNode(xmlNode, "", "", ref operatorStack, ref valueQueue))
            {

                // For each operator adding parenthesis before starting 
                StringBuilder sbTmp = new StringBuilder();
                operatorStack.ToList().ForEach(x => sbTmp.Append("("));
                sb.Append(sbTmp.ToString());

                while (valueQueue.Count > 0)
                {
                    if (operatorStack.Count > 0)
                    {
                        strOperator = operatorStack.Pop();

                    }
                    else
                    {
                        strOperator = string.Empty;
                    }

                    sb.Append(valueQueue.Dequeue());

                    // After each logical operation closing parenthesis 
                    if (previousOp != string.Empty)
                        sb.Append(")");

                    if (strOperator != string.Empty)
                        sb.Append(" " + strOperator + " ");

                    previousOp = strOperator;
                }
            }
            isSuccess = true;
        }
        catch (Exception)
        {
            isSuccess = false;
        }

        return isSuccess;
    }

    private static bool ProcessRecursiveWhereNode(XmlNode xmlNode, string strOperatorValue, string strOperatorType, ref Stack<string> operatorStack, ref Queue<string> valueQueue)
    {
        bool isSuccess = false;
        string fieldName = string.Empty;
        string value = string.Empty;
        string thisIterationOperatorType = string.Empty;
        string thisIterationOperatorValue = string.Empty;

        try
        {
            XmlNodeList nodeList = xmlNode.ChildNodes;

            //Get Child node - Possible tags {<Or>, <And>, <Eq>, <Neq>, <Gt>, <Lt>, <Geq>, <Leq>, </BeginsWith>, <Contains>, <IsNotNull>, <IsNull>, <FieldRef>, <Value>}
            foreach (XmlNode node in nodeList)
            {
                thisIterationOperatorType = string.Empty;
                thisIterationOperatorValue = string.Empty;

                //Check if it's one of these tag: <Or>, <And>, <Eq>, <Neq>, <Gt>, <Lt>, <Geq>, <Leq>, </BeginsWith>, <Contains>, <IsNotNull>, <IsNull>
                thisIterationOperatorValue = GetOperatorString(node.Name, out thisIterationOperatorType);

                if (thisIterationOperatorType == "statement")
                    operatorStack.Push(thisIterationOperatorValue);

                //It's one of these tag: <Or>, <And>, <Eq>, <Neq>, <Gt>, <Lt>, <Geq>, <Leq>, </BeginsWith>, <Contains>, <IsNotNull>, <IsNull>
                if (thisIterationOperatorValue != string.Empty)
                {
                    ProcessRecursiveWhereNode(node, thisIterationOperatorValue, thisIterationOperatorType, ref operatorStack, ref valueQueue);
                }
                else if (strOperatorType != "statement") //It is probably a <FieldRef> or <Value> tag.
                {
                    if (node.Name == "FieldRef")
                        fieldName = node.Attributes["Name"].Value.ToString();
                    else if (node.Name == "Value")
                        value = node.LastChild.Value.ToString();
                }
            }

            if ((strOperatorType == "value" && strOperatorValue != string.Empty && fieldName != string.Empty && value != string.Empty)
                ||
                (strOperatorType == "is" && strOperatorValue != string.Empty && fieldName != string.Empty))
            {
                // if contains a like we don't add the '
                if (strOperatorValue.Contains("LIKE"))
                    valueQueue.Enqueue(string.Format(strOperatorValue, fieldName, value));
                else
                    valueQueue.Enqueue(string.Format(strOperatorValue, fieldName, "'" + value + "'"));
            }

            isSuccess = true;
        }
        catch
        {
            isSuccess = false;
            throw;
        }

        return isSuccess;
    }

    private static string GetOperatorString(string tagName, out string operatorType)
    {
        string operatorString = string.Empty;

        switch (tagName)
        {
            case "Or":
                operatorString = "OR";
                operatorType = "statement";
                break;
            case "And":
                operatorString = "AND";
                operatorType = "statement";
                break;
            case "Eq":
                operatorString = "{0} = {1}";
                operatorType = "value";
                break;
            case "Neq":
                operatorString = "{0} != {1}";
                operatorType = "value";
                break;
            case "Gt":
                operatorString = "{0} > {1}";
                operatorType = "value";
                break;
            case "Lt":
                operatorString = "{0} < {1}";
                operatorType = "value";
                break;
            case "Geq":
                operatorString = "{0} >= {1}";
                operatorType = "value";
                break;
            case "Leq":
                operatorString = "{0} <= {1}";
                operatorType = "value";
                break;
            case "BeginsWith":
                operatorString = "{0} LIKE '{1}%'";
                operatorType = "value";
                break;
            case "Contains":
                operatorString = "{0} LIKE '%{1}%'";
                operatorType = "value";
                break;
            case "IsNotNull":
                operatorString = "{0} IS NOT NULL";
                operatorType = "is";
                break;
            case "IsNull":
                operatorString = "{0} IS NULL";
                operatorType = "is";
                break;

            default:
                operatorString = string.Empty;
                operatorType = string.Empty;
                break;
        }

        return operatorString;
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文