简体   繁体   English

SQL 服务器有条件订购者

[英]SQL Server Conditional Order By

I have a SQL query in SQL Server 2005 that is breaking when I include a conditional order by.我在 SQL Server 2005 中有一个 SQL 查询,当我包含条件订单时,该查询会中断。 When I remove the order by, the query works.当我删除订单时,查询有效。 When I explicitly write the order by condition (eg order by p.Description) it works.当我明确地按条件编写顺序(例如,按 p.Description 顺序)时,它可以工作。 When I include the conditional order by, I get the error,当我包含条件顺序时,我收到错误,

'Conversion failed when converting character string to smalldatetime data type'

SQL Server isn't showing me which line of code caused this error. SQL 服务器没有向我显示导致此错误的代码行。 I'm wondering how I can fix this so I can use the conditional order by or troubleshoot which column is failing in the conversion.我想知道如何解决这个问题,以便我可以使用条件顺序或排除转换中哪个列失败。

declare @SearchTerm nvarchar(255)
declare @SortBy nvarchar(255)
declare @Months int
declare @VendorID int
declare @ProductID int

set @SearchTerm = 'focus'
set @SortBy = 'product'
set @Months = 3
set @VendorID = null
set @ProductID = null

-- This makes it so the @Month will filter by n number of months ago.
declare @PreviousMonths datetime
if @Months is null
    begin
        set @PreviousMonths = 24
    end
else
    begin
        set @PreviousMonths = DateAdd(month, -@Months, GetDate())
    end

select
    a.dsAlertID as AlertID,
    a.ProductID,
    v.VendorID,
    p.Description as ProductName,
    v.LongName as VendorName,
    a.Introduction,
    a.Writeup,
    a.DateAdded 
from
    ev_ds_Alerts a
left outer join
    tblProducts p on a.ProductID = p.ProductID
left outer join
    tblVendors v on v.VendorID = p.VendorID
where
    ( @SearchTerm is null or ( a.Writeup like '% ' + @SearchTerm + '%' or a.Introduction like '% ' + @SearchTerm + '%') )
    and (( @Months is null ) or ( @Months is not null and a.DateAdded >= @PreviousMonths))
    and (( @VendorID is null ) or ( @VendorID is not null and v.VendorID = @VendorID ))
    and (( @ProductID is null ) or ( @ProductID is not null and p.ProductID = @ProductID ))
order by
    case @SortBy
        when 'product' then p.Description
        when 'vendor' then v.LongName
        else a.DateAdded
    end

-- order by p.Description or v.LongName works when explicitly writing them out!

Per the previous answer, try:根据上一个答案,尝试:

order by
    case @SortBy
        when 'product' then p.Description
        when 'vendor' then v.LongName
        else convert(VARCHAR(25),a.DateAdded,20)

This should give you the sort you want, as it will format the date string yyyy-mm-dd hh:mm:ss.这应该为您提供所需的排序,因为它将格式化日期字符串 yyyy-mm-dd hh:mm:ss。

You can use one case for each data type:您可以为每种数据类型使用一种情况:

order by
  case @SortBy
    when 'product' then p.Description
    when 'vendor' then v.LongName
    else ''
  end,
  case @SortBy
    when 'added' then a.DateAdded
    else '1980-01-01'
  end

When using a CASE expression in an ORDER BY -- the data types returned must always be the same.ORDER BY中使用CASE表达式时,返回的数据类型必须始终相同。

You can't cherry pick what you want -- INT, DATETIME, VARCHAR, etc. -- without using dynamic SQL or some form of decision logic (IE: IF ) to breakout the different queries.如果不使用动态 SQL 或某种形式的决策逻辑 (IE: IF ) 来突破不同的查询,您就无法挑选您想要的东西——INT、DATETIME、VARCHAR 等。

In this example you could use CAST/CONVERT to change the DATETIME data type to an appropriate VARCHAR.在此示例中,您可以使用 CAST/CONVERT 将 DATETIME 数据类型更改为适当的 VARCHAR。 But unless you know why the issue is happening, you're likely to do it again in the future.但是,除非您知道问题发生的原因,否则您将来可能会再次这样做。

A NULL in a the list of columns to order by is ignored, so you can break them down by type;列列表中的 NULL 被忽略,因此您可以按类型分解它们;

ORDER BY
    CASE 
       WHEN @SortBy = 'product' THEN p.Description 
       WHEN @SortBy = 'vendor' THEN v.LongName 
    END
    ,
    CASE WHEN @SortBy NOT IN ('product', 'vendor') THEN cda.StartDate END   

Bit ugly for the last else, better if you could;最后一个有点难看,如果可以的话更好;

 CASE WHEN @SortBy = '' THEN cda.StartDate END    

If you care about performance, you might want a different approach: 1. Wrap your select in an inline TVF 2. Use two different SELECTs, so that they can get two different plans, potentially more efficient that the generic one-size-fits-all one plan you are getting now:如果您关心性能,您可能需要一种不同的方法: 1. 将 select 包装在一个内联 TVF 中 2. 使用两个不同的 SELECT,以便他们可以获得两个不同的计划,可能比通用的单一尺寸更有效 -你现在得到的所有一个计划:

IF @SortBy='product' BEGIN
  SELECT AlertID,
(snip)
  FROM MyTvf
  ORDER BY Description ;
  RETURN @@ERROR ;
END 

IF @SortBy='Vendor' BEGIN
  SELECT AlertID,
(snip)
  FROM MyTvf
  ORDER BY LongName ;
  RETURN @@ERROR ;
END 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM