ORDER BY 中带有 CASE WHEN 的 SQL 语句导致类型转换错误

问题描述 投票:0回答:3

执行以下代码会触发错误:

System.Data.SqlClient.SqlException:'无法将 char 值转换为货币。 char 值的语法不正确。

一切都很好,直到我添加了用于排序目的的第二个参数。 为了清晰起见,代码进行了简化。

query as String = "
SELECT a, b, c
FROM DataTable
WHERE c = @PARAM
ORDER BY
    CASE @SORTCOLUMN
        WHEN 1 THEN a
        WHEN 2 THEN b
        WHEN 3 THEN c

    END"

Dim param As String = "myprarameter"
Dim sortcolumn as Integer = 1

result = connection.Query(Of MyType)(query, New With {Key .PARAM = param, Key .SORTCOLUMN = sortcolumn})

更新:

经过数小时的测试,我已将其范围缩小到纯粹的 SQL 问题,而不是 Dapper 或 .NET Framework。

以下是我的发现: 一切正常,直到

CASE WHEN
中使用的所有列都具有相同类型(或可以轻松相互转换的类型甚至值)。一旦列类型不同,值无法转换,则返回类型转换错误。似乎它正在尝试将
CASE WHEN
选择的列的类型转换为第一个
WHEN
列的类型。

举两个例子。为了简单起见,我删除了变量。

这有效:

CREATE TABLE #TestTable1
(col1 money, col2 money)

INSERT INTO #TestTable1
(col1, col2)
VALUES
(1, 30),
(2, 20),
(3, 10)

SELECT col1, col2
FROM  #TestTable1
ORDER BY
    CASE 2
        WHEN 1 THEN col1
        WHEN 2 THEN col2
    END

DROP TABLE #TestTable1

但这不起作用。退货:

无法将字符值转换为货币。 char 值的语法不正确。

CREATE TABLE #TestTable2
(col1 money, col2 varchar(20))

INSERT INTO #TestTable2
(col1, col2)
VALUES
(1, 'cc'),
(2, 'bb'),
(3, 'aa')

SELECT col1, col2
FROM  #TestTable2
ORDER BY
    CASE 2
        WHEN 1 THEN col1
        WHEN 2 THEN col2
    END

DROP TABLE #TestTable2

我使用兼容性级别为 150 的 Azure SQL。 我相应地更新了标题和标签。

更新2: 我正在尝试以第二个参数的形式向 @forpas 解决方案添加一个复杂性,该参数将告诉顺序。我在

CASE
中使用了
CASE
,但这会返回一些语法错误。 仅
ORDER
部分。其余的没变。

ORDER BY
CASE @SORTORDER
WHEN 'a' THEN
   (CASE @SORTCOLUMN
        WHEN 1 THEN col1
        WHEN 2 THEN col2
    END,
    CASE @SORTCOLUMN
        WHEN 3 THEN col3
        WHEN 4 THEN col4
    END) ASC
WHEN 'd' THEN
    (CASE @SORTCOLUMN
        WHEN 1 THEN col1
        WHEN 2 THEN col2
    END,
    CASE @SORTCOLUMN
        WHEN 3 THEN col3
        WHEN 4 THEN col4
    END) DESC
END
sql sql-server vb.net t-sql
3个回答
2
投票

只需将 SQL 创建为 nvarchar 并按如下方式执行:

DECLARE @SQL NVARCHAR(MAX) = N'
    SELECT a, b, c
    FROM DataTable
    WHERE c = @PARAM
    ORDER BY ' + (CASE @SORTCOLUMN WHEN 1 THEN 'a' WHEN 2 THEN 'b' WHEN 3 THEN 'c' ELSE 'a' END);
EXEC sp_Executesql @SQL,
    N'@Param int',
    @Param = @Param;

VB 中

query as String = "DECLARE @SQL NVARCHAR(MAX) = N'SELECT a, b, c FROM DataTable
        WHERE c = @PARAM
        ORDER BY ' + (CASE @SORTCOLUMN WHEN 1 THEN 'a' WHEN 2 THEN 'b' WHEN 3 THEN 'c' ELSE 'a' END);

  EXEC sp_Executesql @SQL,
    N'@Param int',
    @Param = @Param;"

1
投票

一种解决方案是将

CASE
语句拆分为所需的多个
CASE
语句,以便每个语句都包含具有相同或相似可转换数据类型的列:

CREATE TABLE #TestTable2
(col1 money, col2 decimal(18, 2), col3 varchar(20))

INSERT INTO #TestTable2
(col1, col2, col3)
VALUES
(1, 5.5, 'cc'),
(2, 1.8, 'bb'),
(3, 3.3, 'aa');

DECLARE @SORTCOLUMN INT = 1; -- 1 or 2 or 3

SELECT col1, col2, col3
FROM  #TestTable2
ORDER BY
    CASE @SORTCOLUMN 
      WHEN 1 THEN col1
      WHEN 2 THEN col2 
    END,
    CASE @SORTCOLUMN 
      WHEN 3 THEN col3 
    END

DROP TABLE #TestTable2 

查看演示


0
投票

试试这个。

query as String = "
SELECT a, b, c
FROM DataTable
WHERE c = @PARAM
ORDER BY
    CASE @SORTCOLUMN
        WHEN '1' THEN a
        WHEN '2' THEN b
        WHEN '3' THEN c

    END"
© www.soinside.com 2019 - 2024. All rights reserved.