在SQL中,出现了带有CASE WHEN表达式的ORDER BY错误。

huangapple go评论63阅读模式
英文:

ERROR in SQL order by with case when expression

问题

I prepare a SQL query and I use a case-when expression for ordering purposes. If I used req_amount or apply_date as sort_column it works fine. But I use emp_name for sorting, I get this error

> Conversion failed when converting date and/or time from character string.

Please help me to resolve this.

DECLARE @srch_text varchar(50) = 'Cha'
DECLARE @page_no int = 1
DECLARE @page_size int = 10
DECLARE @sort_column varchar(50) = 'emp_name'
DECLARE @order varchar(50) = 'ASC'

if (@order = 'asc' OR @order = 'ASC')
BEGIN
select i.TRN_ID,e.EMP_FULLNAME,i.REQUESTING_AMOUNT,i.BET_APPLY_DATE 
from INTERMEDIATE i
INNER JOIN EMPLOYEE e ON i.BET_EMP_NUMBER = e.EMP_NUMBER 
where e.EMP_FULLNAME LIKE '%'+@srch_text+'%'
ORDER BY 
CASE @sort_column
    WHEN 'req_amount' THEN i.REQUESTING_AMOUNT
    WHEN 'emp_name' THEN  e.EMP_FULLNAME
    WHEN 'apply_date' THEN i.BET_APPLY_DATE
    END asc 
OFFSET @page_size * ((@page_no - 1)) ROWS FETCH NEXT @page_size ROWS ONLY
END
ELSE
BEGIN
select i.TRN_ID,e.EMP_FULLNAME,i.REQUESTING_AMOUNT,i.BET_APPLY_DATE 
from INTERMEDIATE i
INNER JOIN EMPLOYEE e ON i.BET_EMP_NUMBER = e.EMP_NUMBER 
where e.EMP_FULLNAME LIKE '%'+@srch_text+'%'
ORDER BY 
CASE @sort_column
    WHEN 'req_amount' THEN i.REQUESTING_AMOUNT
    WHEN 'emp_name' THEN  e.EMP_FULLNAME
    WHEN 'apply_date' THEN i.BET_APPLY_DATE
    END desc 
OFFSET @page_size * ((@page_no - 1)) ROWS FETCH NEXT @page_size ROWS ONLY
END

(Note: The code you provided includes HTML character codes for single quotes. I've retained them in the translation.)

英文:

I prepare a SQL query and I use a case-when expression for ordering purposes. If I used req_amount or apply_date as sort_column it works fine. But I use emp_name for sorting, I get this error

> Conversion failed when converting date and/or time from character string.

Please help me to resolve this.

DECLARE @srch_text varchar(50) = 'Cha'
DECLARE @page_no int = 1
DECLARE @page_size int = 10
DECLARE @sort_column  varchar(50) = 'emp_name'
DECLARE @order varchar(50) = 'ASC'
if (@order  = 'asc' OR @order = 'ASC')
BEGIN
select i.TRN_ID,e.EMP_FULLNAME,i.REQUESTING_AMOUNT,i.BET_APPLY_DATE 
from INTERMEDIATE i
INNER JOIN EMPLOYEE e ON i.BET_EMP_NUMBER = e.EMP_NUMBER 
where e.EMP_FULLNAME LIKE '%'+@srch_text+'%'
ORDER BY 
CASE @sort_column
WHEN 'req_amount' THEN i.REQUESTING_AMOUNT
WHEN 'emp_name' THEN  e.EMP_FULLNAME
WHEN 'apply_date' THEN i.BET_APPLY_DATE
END	  asc 
OFFSET @page_size * ((@page_no - 1)) ROWS FETCH NEXT @page_size ROWS ONLY
END
ELSE
BEGIN
select i.TRN_ID,e.EMP_FULLNAME,i.REQUESTING_AMOUNT,i.BET_APPLY_DATE 
from INTERMEDIATE i
INNER JOIN EMPLOYEE e ON i.BET_EMP_NUMBER = e.EMP_NUMBER 
where e.EMP_FULLNAME LIKE '%'+@srch_text+'%'
ORDER BY 
CASE @sort_column
WHEN 'req_amount' THEN i.REQUESTING_AMOUNT
WHEN 'emp_name' THEN  e.EMP_FULLNAME
WHEN 'apply_date' THEN i.BET_APPLY_DATE
END	desc 
OFFSET @page_size * ((@page_no - 1)) ROWS FETCH NEXT @page_size ROWS ONLY
END

答案1

得分: 1

以下是翻译好的部分:

你可以使用不同的 ORDER BY 表达式。

SELECT
  i.TRN_ID,
  e.EMP_FULLNAME,
  i.REQUESTING_AMOUNT,
  i.BET_APPLY_DATE 
FROM INTERMEDIATE i
INNER JOIN EMPLOYEE e ON i.BET_EMP_NUMBER = e.EMP_NUMBER 
WHERE e.EMP_FULLNAME LIKE ''' + @srch_text + '''
ORDER BY 
  CASE WHEN @order = 'ASC' AND @sort_column = 'req_amount'  THEN i.REQUESTING_AMOUNT END,
  CASE WHEN @order = 'ASC' AND @sort_column = 'emp_name'    THEN e.EMP_FULLNAME END,
  CASE WHEN @order = 'ASC' AND @sort_column = 'apply_date'  THEN i.BET_APPLY_DATE END,
  CASE WHEN @order <> 'ASC' AND @sort_column = 'req_amount' THEN i.REQUESTING_AMOUNT END,
  CASE WHEN @order <> 'ASC' AND @sort_column = 'emp_name'   THEN e.EMP_FULLNAME END,
  CASE WHEN @order <> 'ASC' AND @sort_column = 'apply_date' THEN i.BET_APPLY_DATE END
OFFSET @page_size * ((@page_no - 1)) ROWS
FETCH NEXT @page_size ROWS ONLY;

说到这一点,最好使用动态 SQL,因为这基本上是一个多功能查询。这意味着索引将得到正确使用(尽管通配符搜索始终会是一个问题)。

请注意使用 sp_executesql 来传递参数。

DECLARE @sql nvarchar(max) = '
SELECT
  i.TRN_ID,
  e.EMP_FULLNAME,
  i.REQUESTING_AMOUNT,
  i.BET_APPLY_DATE 
FROM INTERMEDIATE i
INNER JOIN EMPLOYEE e ON i.BET_EMP_NUMBER = e.EMP_NUMBER 
WHERE e.EMP_FULLNAME LIKE ''%' + @srch_text + '%''
ORDER BY
  ' +

  CASE @sort_column
  WHEN 'req_amount' THEN 'i.REQUESTING_AMOUNT'
  WHEN 'emp_name'   THEN 'e.EMP_FULLNAME'
  WHEN 'apply_date' THEN 'i.BET_APPLY_DATE'
  ELSE '1'
  END +

  IIF(@order = 'ASC', ' ASC', ' DESC ') +
OFFSET @page_size * ((@page_no - 1)) ROWS
FETCH NEXT @page_size ROWS ONLY;
';

PRINT @sql;  -- 你的朋友

EXEC sp_executesql @sql,
  N'@srch_text varchar(200),
    @page_size bigint,
    @page_no bigint',
  @srch_text = @srch_text,
  @page_size = @page_size,
  @page_no = @page_no;

你可能想阅读 https://stackoverflow.com/questions/70519518/is-there-any-better-option-to-apply-pagination-without-applying-offset-in-sql-se/70520457#70520457,该页面解释了为什么一般情况下 OFFSET FETCH 较慢,以及应该采取的替代方法。

英文:

You can use separate ORDER BY expressions.

SELECT
  i.TRN_ID,
  e.EMP_FULLNAME,
  i.REQUESTING_AMOUNT,
  i.BET_APPLY_DATE 
FROM INTERMEDIATE i
INNER JOIN EMPLOYEE e ON i.BET_EMP_NUMBER = e.EMP_NUMBER 
WHERE e.EMP_FULLNAME LIKE &#39;%&#39; + @srch_text + &#39;%&#39;
ORDER BY 
  CASE WHEN @order = &#39;ASC&#39; AND @sort_column = &#39;req_amount&#39;  THEN i.REQUESTING_AMOUNT END,
  CASE WHEN @order = &#39;ASC&#39; AND @sort_column = &#39;emp_name&#39;    THEN e.EMP_FULLNAME END,
  CASE WHEN @order = &#39;ASC&#39; AND @sort_column = &#39;apply_date&#39;  THEN i.BET_APPLY_DATE END,
  CASE WHEN @order &lt;&gt; &#39;ASC&#39; AND @sort_column = &#39;req_amount&#39; THEN i.REQUESTING_AMOUNT END,
  CASE WHEN @order &lt;&gt; &#39;ASC&#39; AND @sort_column = &#39;emp_name&#39;   THEN e.EMP_FULLNAME END,
  CASE WHEN @order &lt;&gt; &#39;ASC&#39; AND @sort_column = &#39;apply_date&#39; THEN i.BET_APPLY_DATE END
OFFSET @page_size * ((@page_no - 1)) ROWS
FETCH NEXT @page_size ROWS ONLY;

Hvaing said that, it's probably better to just use dynamic SQL, as this is basically a Kitchen Sink Query. This means that indexes will get used properly (although the wildcard search is always going to be a problem).

Note the use of sp_executesql to pass parameters in.

DECLARE @sql nvarchar(max) = &#39;
SELECT
  i.TRN_ID,
  e.EMP_FULLNAME,
  i.REQUESTING_AMOUNT,
  i.BET_APPLY_DATE 
FROM INTERMEDIATE i
INNER JOIN EMPLOYEE e ON i.BET_EMP_NUMBER = e.EMP_NUMBER 
WHERE e.EMP_FULLNAME LIKE &#39;&#39;%&#39;&#39; + @srch_text + &#39;&#39;%&#39;&#39;
ORDER BY
  &#39; +

  CASE @sort_column
  WHEN &#39;req_amount&#39; THEN &#39;i.REQUESTING_AMOUNT&#39;
  WHEN &#39;emp_name&#39;   THEN &#39;e.EMP_FULLNAME&#39;
  WHEN &#39;apply_date&#39; THEN &#39;i.BET_APPLY_DATE&#39;
  ELSE &#39;1&#39;
  END +

  IIF(@order = &#39;ASC&#39;, &#39; ASC&#39;, &#39; DESC &#39;) + &#39;
OFFSET @page_size * ((@page_no - 1)) ROWS
FETCH NEXT @page_size ROWS ONLY;
&#39;;

PRINT @sql;  -- your friend

EXEC sp_executesql @sql,
  N&#39;@srch_text varchar(200),
    @page_size bigint,
    @page_no bigint&#39;,
  @srch_text = @srch_text
  @page_size = @page_size,
  @page_no = @page_no;

You might want to take a read of https://stackoverflow.com/questions/70519518/is-there-any-better-option-to-apply-pagination-without-applying-offset-in-sql-se/70520457#70520457 which explains why OFFSET FETCH is slow in general, and what to do instead.

huangapple
  • 本文由 发表于 2023年6月13日 15:08:00
  • 转载请务必保留本文链接:https://go.coder-hub.com/76462429.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定