在 PHP 中使用 SQL “WITH”子句

Posted

技术标签:

【中文标题】在 PHP 中使用 SQL “WITH”子句【英文标题】:Using SQL "WITH" Clause in PHP 【发布时间】:2019-08-28 13:57:35 【问题描述】:

好的,我的环境是 XAMPP 7.3.8,我使用 php 和 MSSQL 数据库。我已经编写了一些代码来查询数据库,并且工作非常好我遇到的这个问题是,当我想将查询包装在“WITH”子句中时,它会停止工作。我无法理解为什么!

我尝试过所有类型的反引号、单引号和双引号。我只是不知道我在哪里搞砸了!

工作代码:

$sql = "SELECT CASE WHEN CHARINDEX('%',\"Name\")>0 THEN SUBSTRING(\"Name\",1,CHARINDEX('_',\"Name\")-1) ELSE \"Name\" END as \"Full Package Name\",
    CASE WHEN CHARINDEX('_',\"Name\")> 0 THEN (select left(\"Name\", charindex('_', \"Name\", charindex('_', \"Name\", charindex('_', \"Name\", charindex('_', \"Name\", charindex('_', \"Name\" )+1)+1)+1)+1)-1)) ELSE \"Name\" END as \"Package Name\",
    CASE WHEN CHARINDEX('_',\"Name\")> 0 THEN SUBSTRING(\"Name\", CHARINDEX('_',\"Name\",CHARINDEX('_',\"Name\", (CHARINDEX('_',\"Name\",(CHARINDEX('_',\"Name\",(CHARINDEX('_',\"Name\")+1))+1))+1))+1)+1,20) ELSE \"Name\" END as 'Version'
    FROM vItem WHERE \"Name\" LIKE 'pkg%'
    AND \"Name\" NOT LIKE 'XPF %'
    AND \"Name\" NOT LIKE 'pkgc%'
    AND \"Name\" NOT LIKE 'PKG_ADD_%'
    AND \"Name\" NOT LIKE '%_SWV%'
    AND \"Name\" NOT LIKE '% - %'
    AND \"Name\" NOT LIKE '%_BETA'
    AND \"Name\" NOT LIKE '%SV1'
    AND \"Name\" NOT LIKE '% Detection%'
    AND CreatedDate > '2016-1-01 01:50:58.120'";

不工作的代码:

$sql = "WITH DATASET AS";
$sql .= "(";
$sql .= "SELECT CASE WHEN CHARINDEX('%',\"Name\")>0 THEN SUBSTRING(\"Name\",1,CHARINDEX('_',\"Name\")-1) ELSE \"Name\" END as \"Full Package Name\",
        CASE WHEN CHARINDEX('_',\"Name\")> 0 THEN (select left(\"Name\", charindex('_', \"Name\", charindex('_', \"Name\", charindex('_', \"Name\", charindex('_', \"Name\", charindex('_', \"Name\" )+1)+1)+1)+1)-1)) ELSE \"Name\" END as \"Package Name\",
        CASE WHEN CHARINDEX('_',\"Name\")> 0 THEN SUBSTRING(\"Name\", CHARINDEX('_',\"Name\",CHARINDEX('_',\"Name\", (CHARINDEX('_',\"Name\",(CHARINDEX('_',\"Name\",(CHARINDEX('_',\"Name\")+1))+1))+1))+1)+1,20) ELSE \"Name\" END as 'Version'
        FROM vItem WHERE \"Name\" LIKE 'pkg%'
        AND \"Name\" NOT LIKE 'XPF %'
        AND \"Name\" NOT LIKE 'pkgc%'
        AND \"Name\" NOT LIKE 'PKG_ADD_%'
        AND \"Name\" NOT LIKE '%_SWV%'
        AND \"Name\" NOT LIKE '% - %'
        AND \"Name\" NOT LIKE '%_BETA'
        AND \"Name\" NOT LIKE '%SV1'
        AND \"Name\" NOT LIKE '% Detection%'
        AND CreatedDate > '2016-1-01 01:50:58.120'";
$sql .= ")";
$sql .= "SELECT * FROM Dataset WHERE RowNum <= 3";

这是我尝试在 PHP 中运行的 SQL 查询,它在 SQL SMS 中运行良好:

WITH Dataset AS (
select
    CASE WHEN CHARINDEX('%',Name)>0
         THEN SUBSTRING(Name,1,CHARINDEX('_',Name)-1) 
         ELSE Name END as 'Full Package Name',
    CASE WHEN CHARINDEX('_',Name)> 0
         THEN (select left(Name, charindex('_', Name, charindex('_', Name, charindex('_', Name, charindex('_', Name, charindex('_', Name )+1)+1)+1)+1)-1))
         ELSE Name END as 'Package Name',
    CASE WHEN CHARINDEX('_',Name)> 0
         THEN SUBSTRING(name, CHARINDEX('_',Name,CHARINDEX('_',name, (CHARINDEX('_',name,(CHARINDEX('_',name,(CHARINDEX('_',name)+1))+1))+1))+1)+1,20)
         ELSE Name END as 'Version',
         ROW_NUMBER() OVER (PARTITION BY (select left(Name, charindex('_', Name, charindex('_', Name, charindex('_', Name, charindex('_', Name, charindex('_', Name )+1)+1)+1)+1)-1)) ORDER BY name DESC) AS RowNum         

from vItem WHERE Name LIKE 'pkg%'
and Name not like 'XPF %'
and Name not like '%.%'
and Name not like '%_SWV%'
and Name not like '% - %'
and Name not like '%_BETA'
and Name not like '%SV1'
and Name not like '% Detection%'
and Name not like 'PKG_ADD_%'
--and CreatedDate >'2016-1-01 01:50:58.120'
)

SELECT * FROM Dataset WHERE RowNum <= 3

这是完整的 PHP 代码:

elseif(isset($_POST['PKGList'])) 
        $sql = "WITH \"Dataset\" as";
        $sql .= "(";
        $sql .= "SELECT CASE WHEN CHARINDEX('%',\"Name\")>0 THEN SUBSTRING(\"Name\",1,CHARINDEX('_',\"Name\")-1) ELSE \"Name\" END as \"Full Package Name\",
        CASE WHEN CHARINDEX('_',\"Name\")> 0 THEN (select left(\"Name\", charindex('_', \"Name\", charindex('_', \"Name\", charindex('_', \"Name\", charindex('_', \"Name\", charindex('_', \"Name\" )+1)+1)+1)+1)-1)) ELSE \"Name\" END as \"Package Name\",
        CASE WHEN CHARINDEX('_',\"Name\")> 0 THEN SUBSTRING(\"Name\", CHARINDEX('_',\"Name\",CHARINDEX('_',\"Name\", (CHARINDEX('_',\"Name\",(CHARINDEX('_',\"Name\",(CHARINDEX('_',\"Name\")+1))+1))+1))+1)+1,20) ELSE \"Name\" END as \"Version\",
        FROM vItem WHERE \"Name\" LIKE 'pkg%'
        AND \"Name\" NOT LIKE 'XPF %'
        AND \"Name\" NOT LIKE 'pkgc%'
        AND \"Name\" NOT LIKE 'PKG_ADD_%'
        AND \"Name\" NOT LIKE '%_SWV%'
        AND \"Name\" NOT LIKE '% - %'
        AND \"Name\" NOT LIKE '%_BETA'
        AND \"Name\" NOT LIKE '%SV1'
        AND \"Name\" NOT LIKE '% Detection%'
        AND CreatedDate > '2016-1-01 01:50:58.120'";
        $sql .= ")";
        $sql .= "SELECT * FROM Dataset WHERE RowNum <= 3";

        $params = array();
        $options =  array( "Scrollable" => SQLSRV_CURSOR_KEYSET );
        $results = sqlsrv_query( $conn, $sql , $params, $options );
        $row_count = sqlsrv_num_rows( $results );
        print_r(sqlsrv_errors(), true);
        if ($row_count === false)
            echo "Error accessing package data.";
        else
            echo "";
            //echo $row_count;
            echo "<table class=\"darkTable\">";
            echo "<tr>
            <th>Full Package Name | $row_count Packages</th>
            <th>Package Name</th>
            <th>Verison</th>
            <th>Build</th>
            </tr>";
        while($row = sqlsrv_fetch_array( $results))   //Creates a loop to loop through results
            echo "<tr><td>" . $row['Full Package Name'] . "</td><td>" .  $row['Package Name'] . "</td><td>" .  $row['Version'] . "</td><td><input type=\"submit\" name=\"PKGList\" value=\"BUILD\" class=\"btn btn-primary\"></td></tr>";  //$row['index'] the index here is a field name
            
            echo "</table>";

    sqlsrv_close($conn);
    $_SESSION['message'] = "Query successfully sent: ".$sql;
     else 

    

【问题讨论】:

你遇到了什么错误? 请在sqlsrv_query() 调用后执行print_r(sqlsrv_errors(), true); 并发布错误消息。谢谢。 @demo7up 没有完整的 PHP 代码很难,但我猜你的代码有错误(例如,$sql = 'WITH DATASET AS"; 应该是 $sql = "WITH DATASET AS";)。 @demo7up 请检查来自sqlsrv_query 的结果并发布结果($results = sqlsrv_query( $conn, $sql , $params, $options ); if ($results === false) echo "Error (sqlsrv_query): ".print_r(sqlsrv_errors(), true); exit;)。您的 T-SQL 语句中有错误。再次感谢。 @demo7up 您在Dataset 中没有RowNum 列,所以WHERE RowNum &lt;= 3 很可能是您出错的原因。 【参考方案1】:

一种可能的解释是RowNum 在您的DataSet CTE 中没有列。只需更正您的 T-SQL 语句并包含 RowNum 列即可。

<?php

$sql = "WITH DATASET AS";
$sql .= "(";
$sql .= "SELECT 
        -- Include RowNum column here ...
        --ROW_NUMBER() OVER (...) As RowNum,
        CASE WHEN CHARINDEX('%',\"Name\")>0 THEN SUBSTRING(\"Name\",1,CHARINDEX('_',\"Name\")-1) ELSE \"Name\" END as \"Full Package Name\",
        CASE WHEN CHARINDEX('_',\"Name\")> 0 THEN (select left(\"Name\", charindex('_', \"Name\", charindex('_', \"Name\", charindex('_', \"Name\", charindex('_', \"Name\", charindex('_', \"Name\" )+1)+1)+1)+1)-1)) ELSE \"Name\" END as \"Package Name\",
        CASE WHEN CHARINDEX('_',\"Name\")> 0 THEN SUBSTRING(\"Name\", CHARINDEX('_',\"Name\",CHARINDEX('_',\"Name\", (CHARINDEX('_',\"Name\",(CHARINDEX('_',\"Name\",(CHARINDEX('_',\"Name\")+1))+1))+1))+1)+1,20) ELSE \"Name\" END as 'Version'
        FROM vItem WHERE \"Name\" LIKE 'pkg%'
        AND \"Name\" NOT LIKE 'XPF %'
        AND \"Name\" NOT LIKE 'pkgc%'
        AND \"Name\" NOT LIKE 'PKG_ADD_%'
        AND \"Name\" NOT LIKE '%_SWV%'
        AND \"Name\" NOT LIKE '% - %'
        AND \"Name\" NOT LIKE '%_BETA'
        AND \"Name\" NOT LIKE '%SV1'
        AND \"Name\" NOT LIKE '% Detection%'
        AND CreatedDate > '2016-1-01 01:50:58.120'";
$sql .= ")";
$sql .= "SELECT * FROM Dataset WHERE RowNum <= 3";

...
?>

【讨论】:

【参考方案2】:

这不是一个确切的答案,但这里的一种解决方法是内联 CTE:

SELECT *
FROM
(
    SELECT CASE WHEN CHARINDEX('%', Name) > 0
                THEN SUBSTRING(Name, 1, CHARINDEX('_', Name) - 1)
                ELSE Name END AS [Full Package Name],
    ...,
    ROW_NUMBER() OVER (PARTITION BY (select left(Name, charindex('_', Name, charindex('_', Name, charindex('_', Name, charindex('_', Name, charindex('_', Name )+1)+1)+1)+1)-1)) ORDER BY name DESC) AS RowNum         
    FROM vItem
    ...
) Dataset
WHERE RowNum <= 3;

假设您使用 CTE 所涉及的唯一问题,这应该可行。

【讨论】:

以上是关于在 PHP 中使用 SQL “WITH”子句的主要内容,如果未能解决你的问题,请参考以下文章

如何使用SQL中的“With”子句更新值

WITH子句中的PL/SQL

如何在标准 SQL 的 WHERE 子句中使用 WITH 子查询作为选项列表

JOOQ:使用 WITH 子句创建子查询(使用纯 SQL)

哪个更快? Spark SQL with Where 子句或在 Spark SQL 之后在 Dataframe 中使用过滤器

包含使用 with 子句的 sql 的 oracle 管道函数