SQL просмотр запроса "подзапрос вернул более 1 значения" - PullRequest
0 голосов
/ 07 января 2020

Я использую запрос для представления, которое также используется для отчетов SSRS без каких-либо проблем в течение более 2 лет, выполняя его каждый месяц. Это запрос:

SELECT  
    DISTINCT 
    Code= D.LocalityCode,
    [District Name]=D.LocalityName,
    Status=UPPER(D.Status),
    [Company No]=F.CompanyNumber,
    [CompanyB No]=F.CompanyBNumber,
    [Incorp date]=case when F.DateIncorp = '1900-01-01 00:00:00.000' Then NULL else F.DateIncorp end,
    [CompanyB date]=case when F.DateCompanyB = '1900-01-01 00:00:00.000' Then NULL else F.DateCompanyB end,
    Salutation=CASE WHEN D.Status = 'LAPSED' THEN 'S.A. OF ' + UPPER(E.InstitutionName) WHEN D.Status = 'ACTIVE' THEN 'OF ' + UPPER(E.InstitutionName) ELSE '' END,
    [Sec Code]=dbo.SecCodeLookup(E.LocalityID),
    [Treas Code]=dbo.TreCodeLookup(E.LocalityID),
    [Sec Name]=dbo.SecNameLookup(E.LocalityID),
    [Treas Name]=dbo.TreNameLookup(E.LocalityID),
    [S Building]=(SELECT Building FROM SecAddressLookup(E.LocalityID)),
    [S Street]=(SELECT Street FROM SecAddressLookup(E.LocalityID)),
    [S Town]=(SELECT Town FROM SecAddressLookup(E.LocalityID)),
    [S Postcode]=(SELECT Postcode FROM SecAddressLookup(E.LocalityID)),
    [T Building]=(SELECT Building FROM TreAddressLookup(E.LocalityID)),
    [T Street]=(SELECT Street FROM TreAddressLookup(E.LocalityID)),
    [T Town]=(SELECT Town FROM TreAddressLookup(E.LocalityID)),
    [T Postcode]=(SELECT Postcode FROM TreAddressLookup(E.LocalityID))
FROM
    tblLocality D
    LEFT JOIN tblInstitution E ON D.LocalityID = E.LocalityID
    LEFT JOIN tblCompanyDetail F ON E.CompanyDetailID = F.CompanyDetailID
    LEFT JOIN tblInstitutionHistory G ON E.InstitutionID = G.InstitutionID
    LEFT JOIN tblStatusDetail H ON G.StatusDetailID = H.StatusDetailID

WHERE D.LocalityID NOT IN ('5150','5156','5149')    


GO

TreNameLookup fuction:

USE [db_1]
GO
/****** Object:  UserDefinedFunction [dbo].[TreNameLookup]   ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO


CREATE FUNCTION [dbo].[TreNameLookup](@LocalityID INT) RETURNS NVARCHAR(MAX) AS
BEGIN

    RETURN (
                SELECT FullName FROM
                (SELECT Title + ' ' + FirstName + ' ' + LastName  AS FullName, COUNT(*) AS QTY
                    FROM tblInstitution A
                        INNER JOIN tblInstitutionHistory B ON A.InstitutionID = B.InstitutionID
                        INNER JOIN tblInstitutionMembers C  ON B.InstitutionHistoryID = C.InstitutionHistoryID
                        INNER JOIN tblIndividual D on c.IndividualID = d.IndividualID
                    WHERE b.TYear in ((SELECT MAX(TYear) FROM tblInstitutionHistory),
                    (SELECT MAX(TYear)-1 FROM tblInstitutionHistory),
                    (SELECT MAX(TYear)-2 FROM tblInstitutionHistory),
                    (SELECT MAX(TYear)-3 FROM tblInstitutionHistory),
                    (SELECT MAX(TYear)-4 FROM tblInstitutionHistory),
                    (SELECT MAX(TYear)-5 FROM tblInstitutionHistory),
                    (SELECT MAX(TYear)-6 FROM tblInstitutionHistory),
                    (SELECT MAX(TYear)-7 FROM tblInstitutionHistory),
                    (SELECT MAX(TYear)-8 FROM tblInstitutionHistory),
                    (SELECT MAX(TYear)-9 FROM tblInstitutionHistory))   
                        AND CurrentMember = 1 
                        AND MemberTypeID=4 
                        AND LocalityID=@LocalityID

                        AND LocalityID NOT IN ('5150','5156','5149')
                    GROUP BY Title + ' ' + FirstName + ' ' + LastName  
                    HAVING COUNT(*) <=1                 
                )RES

            )


END

SecAddressLookup функция:

USE [db_1]
GO
/****** Object:  UserDefinedFunction [dbo].[SecAddressLookup]     ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO



ALTER FUNCTION [dbo].[SecAddressLookup](@LocalityID INT) 

    RETURNS @SecAddress TABLE
        (
            Building    nvarchar(250),
            Street      nvarchar(250),
            Town        nvarchar(200),
            Postcode    nvarchar(100)
        )
    AS
    BEGIN
        INSERT @SecAddress  
            SELECT Building,street,Town,Postcode FROM
            (
            SELECT
                F.Building,F.Street,F.Town,F.Postcode,COUNT(*) AS QTY  
                FROM tblInstitution A
                    INNER JOIN tblInstitutionHistory B ON A.InstitutionID = B.InstitutionID
                    INNER JOIN tblInstitutionMembers C  ON B.InstitutionHistoryID = C.InstitutionHistoryID
                    INNER JOIN tblIndividual D ON c.IndividualID = d.IndividualID
                    INNER JOIN tblHousehold E ON D.IndividualID = E.IndividualID
                    INNER JOIN tblAddress F ON E.AddressID = F.AddressID
                WHERE b.TYear in ((SELECT MAX(TYear) FROM tblInstitutionHistory),
                    (SELECT MAX(TYear)-1 FROM tblInstitutionHistory),
                    (SELECT MAX(TYear)-2 FROM tblInstitutionHistory),
                    (SELECT MAX(TYear)-3 FROM tblInstitutionHistory),
                    (SELECT MAX(TYear)-4 FROM tblInstitutionHistory),
                    (SELECT MAX(TYear)-5 FROM tblInstitutionHistory),
                    (SELECT MAX(TYear)-6 FROM tblInstitutionHistory),
                    (SELECT MAX(TYear)-7 FROM tblInstitutionHistory),
                    (SELECT MAX(TYear)-8 FROM tblInstitutionHistory),
                    (SELECT MAX(TYear)-9 FROM tblInstitutionHistory))
                    AND CurrentMember = 1 
                    AND MemberTypeID=1 
                    AND A.LocalityID=@LocalityID

                    AND E.CurrentAddress=1

                    and A.LocalityID NOT IN ('5150','5156','5149') 
                GROUP BY F.Building,F.Street,F.Town,F.Postcode
                HAVING COUNT(*) <=1 
                    )RES

        RETURN
    END

SecCodeLookup fuction:

CREATE FUNCTION [dbo].[SecCodeLookup](@LocalityID INT) RETURNS NVARCHAR(15) AS
BEGIN

    RETURN (
                SELECT MyID FROM 
                (SELECT MyID, COUNT(*) AS QTY 
                    FROM tblInstitution A
                        INNER JOIN tblInstitutionHistory B ON A.InstitutionID = B.InstitutionID
                        INNER JOIN tblInstitutionMembers C  ON B.InstitutionHistoryID = C.InstitutionHistoryID
                        INNER JOIN tblIndividual D on c.IndividualID = d.IndividualID
                    WHERE b.TYear in ((SELECT MAX(TYear) FROM tblInstitutionHistory),
                    (SELECT MAX(TYear)-1 FROM tblInstitutionHistory),
                    (SELECT MAX(TYear)-2 FROM tblInstitutionHistory),
                    (SELECT MAX(TYear)-3 FROM tblInstitutionHistory),
                    (SELECT MAX(TYear)-4 FROM tblInstitutionHistory),
                    (SELECT MAX(TYear)-5 FROM tblInstitutionHistory),
                    (SELECT MAX(TYear)-6 FROM tblInstitutionHistory),
                    (SELECT MAX(TYear)-7 FROM tblInstitutionHistory),
                    (SELECT MAX(TYear)-8 FROM tblInstitutionHistory),
                    (SELECT MAX(TYear)-9 FROM tblInstitutionHistory))
                        AND CurrentMember = 1 
                        AND MemberTypeID=1
                        AND LocalityID=@LocalityID

                        and LocalityID NOT IN ('5150','5156','5149')
                    GROUP BY MyID
                    HAVING COUNT(*) <=1                     
                )RES
            )


END

Сегодня я попробовал другое время, и я получаю эту ошибку:

Сообщение 512, Уровень 16, Состояние 1, Строка 4

Подзапрос возвратил больше, чем 1 значение Это недопустимо, если подзапрос следует =,! =, <, <=,>,> = Или когда подзапрос используется в качестве выражения.

Когда я использую запрос для генерации SSRS возвращает отчет:

Произошла ошибка при обработке отчета. (rsProcessingAborted)
Невозможно прочитать следующую строку данных для набора данных DataSet1. (rsErrorReadingNextDataRow)
Для получения дополнительной информации об этой ошибке перейдите на сервер отчетов на локальном сервере или включите удаленные ошибки

В журналах (в \ Reporting Services \ LogFiles):

ui!ReportManager_0-3!1280!01/07/2020-10:10:31:: i INFO: AccessibleTablix value not specified in config file.
library!ReportServer_0-4!1114!01/07/2020-10:10:31:: Call to GetSystemPropertiesAction().
library!ReportServer_0-4!1280!01/07/2020-10:10:32:: Call to GetPermissionsAction(/My Office/Bulk Exports/DistrictExport).
library!ReportServer_0-4!fd8!01/07/2020-10:10:32:: Call to GetSystemPropertiesAction().
library!ReportServer_0-4!fdc!01/07/2020-10:10:32:: Call to GetPropertiesAction(/My Office/Bulk Exports/DistrictExport, PathBased).
library!ReportServer_0-4!fdc!01/07/2020-10:10:32:: Call to GetSystemPermissionsAction().
library!ReportServer_0-4!fdc!01/07/2020-10:10:32:: Call to GetSystemPropertiesAction().
library!ReportServer_0-4!fdc!01/07/2020-10:10:33:: i INFO: RenderForNewSession('/My Office/Bulk Exports/DistrictExport')
processing!ReportServer_0-4!fdc!01/07/2020-10:13:18:: e ERROR: Throwing Microsoft.ReportingServices.ReportProcessing.ReportProcessingException: , Microsoft.ReportingServices.ReportProcessing.ReportProcessingException: Cannot read the next data row for the dataset DataSet1. ---> System.Data.SqlClient.SqlException: Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression.
   at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection)
   at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj)
   at System.Data.SqlClient.TdsParser.Run(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj)
   at System.Data.SqlClient.SqlDataReader.HasMoreRows()
   at System.Data.SqlClient.SqlDataReader.ReadInternal(Boolean setTimeout)
   at Microsoft.ReportingServices.DataExtensions.DataReaderWrapper.Read()
   at Microsoft.ReportingServices.DataExtensions.MappingDataReader.GetNextRow()
   --- End of inner exception stack trace ---;

Я также проверил данные и ошибки при выборке 135-й строки, но это точно те же данные, что и 1 год go.

В качестве теста я удалил эти строки:

[S Building]=(SELECT Building FROM SecAddressLookup(E.LocalityID)),
[S Street]=(SELECT Street FROM SecAddressLookup(E.LocalityID)),
[S Town]=(SELECT Town FROM SecAddressLookup(E.LocalityID)),
[S Postcode]=(SELECT Postcode FROM SecAddressLookup(E.LocalityID)),
[T Building]=(SELECT Building FROM TreAddressLookup(E.LocalityID)),
[T Street]=(SELECT Street FROM TreAddressLookup(E.LocalityID)),
[T Town]=(SELECT Town FROM TreAddressLookup(E.LocalityID)),
[T Postcode]=(SELECT Postcode FROM TreAddressLookup(E.LocalityID))

и работает только до 102 строк (даже не 134 строк) странно.

Ответы [ 3 ]

1 голос
/ 07 января 2020

Не уверен на 100% без доступа к таблицам или UDF.
Но я догадываюсь, что адресные функции возвращают больше, чем 1 запись.

Тогда, как попытка быстрого и грязного решения, вы можете обернуть эти функции в OUTER APPLY.
с TOP 1, чтобы они возвращали только 1 запись.

SELECT DISTINCT 
    Code= D.LocalityCode,
    [District Name]=D.LocalityName,
    Status=UPPER(D.Status),
    [Company No]=F.CompanyNumber,
    [CompanyB No]=F.CompanyBNumber,
    [Incorp date]=case when F.DateIncorp = '1900-01-01 00:00:00.000' Then NULL else F.DateIncorp end,
    [CompanyB date]=case when F.DateCompanyB = '1900-01-01 00:00:00.000' Then NULL else F.DateCompanyB end,
    Salutation=CASE WHEN D.Status = 'LAPSED' THEN 'S.A. OF ' + UPPER(E.InstitutionName) WHEN D.Status = 'ACTIVE' THEN 'OF ' + UPPER(E.InstitutionName) ELSE '' END,
    [Sec Code] = CodeName.SecCode,
    [Tre Code] = CodeName.TreCode,
    [Sec Name] = CodeName.SecName,
    [Treas Name] = CodeName.TreName,
    [S Building] = SecAddress.Building,
    [S Street] = SecAddress.Street,
    [S Town] = SecAddress.Town,
    [S Postcode] = SecAddress.Postcode,
    [T Building] = TreAddress.Building,
    [T Street] = TreAddress.Street,
    [T Town] = TreAddress.Town,
    [T Postcode] = TreAddress.Postcode
FROM tblLocality D
LEFT JOIN tblInstitution E ON D.LocalityID = E.LocalityID
LEFT JOIN tblCompanyDetail F 
  ON E.CompanyDetailID = F.CompanyDetailID
LEFT JOIN tblInstitutionHistory G 
  ON E.InstitutionID = G.InstitutionID
LEFT JOIN tblStatusDetail H 
  ON G.StatusDetailID = H.StatusDetailID
OUTER APPLY
(
    SELECT TOP 1 l.* 
    FROM dbo.SecAddressLookup(E.LocalityID) l
    ORDER BY l.Building
) AS SecAddress
OUTER APPLY
(
    SELECT TOP 1 l.* 
    FROM dbo.TreAddressLookup(E.LocalityID) l
    ORDER BY l.Building
) AS TreAddress
OUTER APPLY
(
    SELECT TOP 1 
    SecCd.Code AS SecCode,
    TreCd.Code AS TreCode,
    SecNm.FullName AS SecName,
    TreNm.FullName AS TreName
    FROM (SELECT dbo.SecCodeLookup(E.LocalityID) AS Code) AS SecCd
    CROSS JOIN (SELECT dbo.TreCodeLookup(E.LocalityID) AS Code) AS TreCd
    CROSS JOIN dbo.SecNameLookup(E.LocalityID) AS SecNm
    CROSS JOIN dbo.TreNameLookup(E.LocalityID) AS TreNm
    ORDER BY SecNm.FullName DESC, TreNm.FullName DESC
) AS CodeName
WHERE D.LocalityID NOT IN ('5150','5156','5149')    

Но после этого эти UDF и данные должны быть проверены на вашей стороне.
Поскольку все эти UDF не помогут с производительностью.
Возможно, эти запросы можно объединить.

0 голосов
/ 08 января 2020

вы можете использовать Top 1 в вашем подзапросе.

0 голосов
/ 07 января 2020

1) Если поле LocalityID не определено как первичный ключ в таблице tblLocality, при выполнении следующего запроса может быть указано, что виновник:

select LocalityID, count(*) from tblLocality having count(*) >1

2) Если поле LocalityID определено как первичный ключ в таблице tblLocality это означает, что она уникальна, проблема заключается в одной из ваших функций, которые принимают в качестве параметра E.LocalityID. Поскольку у нас нет доступа к коду этих функций, мы можем видеть, какая из них вызывает и как.

Проверьте точку один и пункт два, и вы увидите проблему.

...