2011-06-29 9 views
8

Tengo una consulta SQL en SQL Server 2005 que se está rompiendo cuando incluyo un orden condicional por. Cuando elimino el pedido por, la consulta funciona. Cuando escribo explícitamente el pedido por condición (por ejemplo, orden por p.Descripción), funciona. Cuando incluyo el orden condicionada por, me sale el error,Pedido condicional del servidor SQL Por

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

SQL Server no se me muestran qué línea de código causó este error. Me pregunto cómo puedo solucionar esto para poder usar el orden condicional o solucionar cuál columna está fallando en la conversión.

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, [email protected], 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! 
+0

podrás n Es necesario usar 'CAST' –

+0

Hacer declaraciones de mayúsculas independientes para evitar el tipo de datos de error de conversión –

Respuesta

15

por la respuesta anterior, trate de:

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

Esto debe darle la clasificación que desea, ya que el formato hh cadena de fecha aaaa-mm-dd: mm: ss.

+1

+1 Me alegro de que recordó formatear la fecha como aaaa-mm-dd hh: mm: ss para mantener el orden coherente. –

+0

Esto era exactamente lo que tenía que hacer. Muchas gracias! – Halcyon

6

cuando se utiliza una expresión CASE en un ORDER BY - los datos tipos devueltos debe ser siempre el mismo.

No puede seleccionar lo que desee - INT, DATETIME, VARCHAR, etc. - sin usar SQL dinámico o alguna forma de lógica de decisión (IE: IF) para desglosar las diferentes consultas.

En este ejemplo, podría usar CAST/CONVERT para cambiar el tipo de datos DATETIME a un VARCHAR apropiado. Pero a menos que sepa por qué está sucediendo el problema, es probable que lo haga de nuevo en el futuro.

+0

Eso tiene sentido. ¿Cuál sería una solución apropiada para usar la expresión de caso? – Halcyon

+0

@Halcyon: utilice un 'IF' para separar el manejo del tipo de datos para consultas separadas o SQL dinámico. –

+0

Excelente explicación, pero no explica cómo OP puede realizar el pedido. Según @Neil y @gibeath: casting. –

1

Se ignora un NULL en la lista de columnas para ordenar, por lo que puede desglosarlas por tipo;

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 feo para el último, mejor si puedes;

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

Creo que puede eliminar el segundo caso de su respuesta y simplemente agregar StartDate. En el primer caso, use un else para establecer el espacio por defecto. Ver mi código – niktrs

+0

Es cierto, la diferencia es que siempre se aplica ordenar por fecha (después de la otra orden) que puede o no ser necesario –

11

Puede utilizar uno de los casos para cada tipo de datos:

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 
+0

+1. No había visto tu respuesta y escribí algo similar. – niktrs

0

Si se preocupan por el rendimiento, es posible que desee un enfoque diferente: 1. envolver su selección en una línea TVF 2. Use dos selecciona diferentes, de modo que puedan obtener dos planes diferentes, potencialmente más eficientes que los genéricos de una talla única para todos un solo plan que está recibiendo ahora:

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 
+0

¿Quién bajó la votación, te gustaría elaborar? –

+0

Este es un buen consejo para considerar. – TTT