Subconsulta en una cláusula IN () causando error
-
03-07-2019 - |
Pregunta
Estoy en SQL Server 2005 y recibo un error que estoy bastante seguro de que no debería estar recibiendo.
Msg 512, Level 16, State 1, Procedure spGetSavedSearchesByAdminUser, Line 8 Subquery
returned more than 1 value. This is not permitted when the subquery
follows =, !=, <, <= , >, >= or when the subquery is used as an expression.
Estoy siguiendo el ejemplo # B en este enlace de MSDN.
Mi código de proceso almacenado es el siguiente. Puedo simplificarlo por el bien de esta publicación si así lo solicita:
ALTER PROCEDURE [dbo].[spGetSavedSearchesByAdminUser]
@strUserName varchar(50)
,@bitQuickSearch bit = 0
AS
BEGIN
SELECT [intSearchID] ,strSearchTypeCode ,[strSearchName]
FROM [tblAdminSearches]
WHERE
strUserName = @strUserName
AND
strSearchTypeCode
IN (
CASE @bitQuickSearch
WHEN 1 THEN 'Quick'
ELSE (SELECT strSearchTypeCode FROM tblAdvanceSearchTypes)
END
)
ORDER BY strSearchName
END
He comprobado que no hay una falta de coincidencia en el tipo de datos entre el conjunto de resultados de la subconsulta y el strSearchTypeCode con el que se compara el resultado de la subconsulta.
No veo ninguna razón por la que esto no debería funcionar. Si tiene alguna pista, hágamelo saber.
Solución
Intente reorganizar la consulta para que la expresión booleana aparezca dentro de la subselección, por ejemplo,
ALTER PROCEDURE [dbo].[spGetSavedSearchesByAdminUser]
@strUserName varchar(50)
,@bitQuickSearch bit = 0
AS
BEGIN
SELECT [intSearchID] ,strSearchTypeCode ,[strSearchName]
FROM [tblAdminSearches]
WHERE
strUserName = @strUserName
AND
strSearchTypeCode
IN (SELECT strSearchTypeCode FROM tblAdvanceSearchTypes where @bitQuickSearch=0
UNION
SELECT 'Quick' AS strSearchTypeCode WHERE @bitQuickSearch=1)
ORDER BY strSearchName
END
Otros consejos
No sé si puede usar la sentencia CASE dentro de una cláusula IN de esa manera. Sugeriría reescribir ese bit a:
WHERE strUserName = @strUserName AND (
(@bitQuickSearch = 1 AND strSearchTypeCode = 'Quick')
OR
(strSearchTypeCode IN (SELECT strSearchTypeCode FROM tblAdvanceSearchTypes))
)
o, si realmente te gusta el estilo que tienes ahí:
WHERE strUserName = @strUserName
AND strSearchTypeCode IN (
SELECT CASE @bitQuickSearch WHEN 1 THEN 'Quick' ELSE strSearchTypeCode END
FROM tblAdvanceSearchTypes
)
En general, SQL debería ser lo suficientemente inteligente como para optimizar la tabla si @bitQuickSearch = 1. Pero, verificaría el plan de consulta solo para estar seguro (confianza, pero verificación).
Me parece que este SELECCIONAR:
SELECT strSearchTypeCode FROM tblAdvanceSearchTypes
devuelve múltiples filas, y ese es tu problema. Puedes reescribirlo para que sea:
SELECT TOP 1 strSearchTypeCode FROM tblAdvanceSearchTypes