Search code examples
sqlsql-serveroptimizationcommon-table-expression

SQL CTE Calculate pending totals?


i have a database with several departments, i have a query to select paid, collected and pending payments from invoices and costs, thus they need to have a report showing Collected not paid if > 0, and Paid not collected if < 0 hence i wrote this query but i don't know if it's correct or it can be written otherwise to optimize large data

DECLARE @JobSImport TABLE([Id] int NOT NULL identity(1, 1), [JobNo] int, [JobDate] varchar(10), 
    [DepartmentId] int, [DepartmentName] varchar(200), [CustomerName] varchar(200), [FullPaid] bit);

insert into @JobSImport
select 3862,    '2024-06-21',   16, 'SEA IMPORT',   'Antranik Baljian',             0   union all
select 3861,    '2024-06-20',   16, 'SEA IMPORT',   'Saber Industrial Corporation', 0   union all
select 3860,    '2024-06-20',   16, 'SEA IMPORT',   'Antranik Baljian',             0   union all
select 3859,    '2024-06-20',   16, 'SEA IMPORT',   'Antranik Baljian',             0   union all
select 3858,    '2024-06-19',   16, 'SEA IMPORT',   'Mr.Rafik Bader',               0   union all
select 3857,    '2024-06-14',   16, 'SEA IMPORT',   'S.M.J ( Offshore )',           0   union all
select 3856,    '2024-06-13',   16, 'SEA IMPORT',   'Oya Trading',                  0   union all
select 3855,    '2024-06-13',   16, 'SEA IMPORT',   'Maalouf General Trading',      0   union all
select 3854,    '2024-06-12',   16, 'SEA IMPORT',   'Mousa Mazloum',                0   union all
select 3853,    '2024-06-11',   16, 'SEA IMPORT',   'Aj Concept Group',             0;


DECLARE @JobSeaExport TABLE([Id] int NOT NULL identity(1, 1), [JobNo] int, [JobDate] varchar(10), 
    [DepartmentId] int, [DepartmentName] varchar(200), [CustomerName] varchar(200), [FullPaid] bit);

insert into @JobSeaExport
select 497,     '6-14-2024',    18, 'SEA EXPORT',   'Antranik Baljian',             0 union all
select 496,     '6-14-2024',    18, 'SEA EXPORT',   'Tala General Trading Company', 0 union all
select 495,     '5-30-2024',    18, 'SEA EXPORT',   'Tb Steel',                     1 union all
select 494,     '5-29-2024',    18, 'SEA EXPORT',   'Inkript Securities',           0 union all
select 493,     '5-15-2024',    18, 'SEA EXPORT',   'Ets Kamel Saad Trading',       1 union all
select 492,     '5-10-2024',    18, 'SEA EXPORT',   'Ali Nour  Eldein',             1 union all
select 491,     '5-8-2024',     18, 'SEA EXPORT',   'Tb Steel',                     1 union all
select 490,     '5-2-2024',     18, 'SEA EXPORT',   'Spedicon Maldives (Pvt) Ltd.', 0 union all
select 489,     '4-22-2024',    18, 'SEA EXPORT',   'Inkript Securities',           1 union all
select 488,     '4-22-2024',    18, 'SEA EXPORT',   'Ets Kamel Saad Trading',       1;


DECLARE @JobSeaClearance TABLE([Id] int NOT NULL identity(1, 1), [JobNo] int, [JobDate] varchar(10), 
    [DepartmentId] int, [DepartmentName] varchar(200), [CustomerName] varchar(200), [FullPaid] bit);

insert into @JobSeaClearance
select 244,     '2024-06-14',   17, 'SEA CLEARANCE',    'Unigaz',                   0 union all
select 243,     '2024-05-14',   17, 'SEA CLEARANCE',    'Pierre Merhej',            0 union all
select 242,     '2024-05-13',   17, 'SEA CLEARANCE',    'Pierre Merhej',            0 union all
select 241,     '2024-05-10',   17, 'SEA CLEARANCE',    'Unicorn Supply Chain Co',  0 union all
select 240,     '2024-05-09',   17, 'SEA CLEARANCE',    'Joseph Fadous Est',        1 union all
select 239,     '2024-03-28',   17, 'SEA CLEARANCE',    'Sucasu',                   0 union all
select 238,     '2024-03-14',   17, 'SEA CLEARANCE',    'Care First Pharmacy',      1 union all
select 237,     '2024-01-15',   17, 'SEA CLEARANCE',    'Custom Roast',             1 union all
select 236,     '2024-01-11',   17, 'SEA CLEARANCE',    'Rafic Daou',               1 union all
select 235,     '2023-12-05',   17, 'SEA CLEARANCE',    'Tb Steel',                 1;

DECLARE @MainInvoices TABLE([Id] int NOT NULL identity(1, 1), [JobId] int, [DepartmentId] int, 
        S_Amount DECIMAL(19, 4), Paid bit);

insert into @MainInvoices
select 3853,    16,     13248.83,       0   union all
select 3854,    16,     4264.40,        0   union all
select 3855,    16,     6641.05,        0   union all
select 3856,    16,     5824.40,        0   union all
select 3857,    16,     6300.00,        0   union all
select 3858,    16,     9420.44,        0   union all
select 3859,    16,     23409.40,       0   union all
select 3860,    16,     7404.40,        0   union all
select 3861,    16,     5008.05,        0   union all
select 3862,    16,     5809.40,        0   union all
select 488,     18,     2170.00,        1   union all
select 489,     18,     2593.00,        1   union all
select 490,     18,     4530.00,        0   union all
select 491,     18,     1950.00,        1   union all
select 492,     18,     1187.00,        1   union all
select 493,     18,     1700.00,        1   union all
select 494,     18,     2645.00,        0   union all
select 495,     18,     2885.00,        1   union all
select 496,     18,     2730.00,        0   union all
select 497,     18,     1930.00,        0   union all
select 235,     17,     399.60,         1   union all
select 235,     17,     52.31,          1   union all
select 235,     17,     4574.32,        1   union all
select 236,     17,     710.40,         1   union all
select 237,     17,     338.55,         1   union all
select 237,     17,     5488.35,        1   union all
select 237,     17,     388.00,         1   union all
select 237,     17,     55.87,          1   union all
select 237,     17,     30.00,          1   union all
select 236,     17,     3223.80,        1   union all
select 236,     17,     670.00,         1   union all
select 236,     17,     84.11,          1   union all
select 238,     17,     432.90,         1   union all
select 239,     17,     705.00,         0   union all
select 240,     17,     780.00,         1   union all
select 241,     17,     250.00,         0   union all
select 242,     17,     876.90,         0   union all
select 243,     17,     826.95,         0   union all
select 238,     17,     1238.99,        1   union all
select 238,     17,     360.00,         1   union all
select 240,     17,     1099.00,        1   union all
select 240,     17,     112.04,         1   union all
select 240,     17,     3745.03,        1   union all
select 239,     17,     26135.00,       1   union all
select 239,     17,     279.33,         0   union all
select 239,     17,     600.00,         0   union all
select 244,     17,     310.80,         0;



DECLARE @CostSheet TABLE([Id] int NOT NULL identity(1, 1), [JobId] int, [DepartmentId] int, 
        S_Amount DECIMAL(19, 4), Paid bit);

insert into @CostSheet
select 3853,    16,     13076.83,       0   union all
select 3854,    16,     3500.00,        0   union all
select 3854,    16,     373.97,         0   union all
select 3855,    16,     6567.83,        0   union all
select 3856,    16,     5640.09,        0   union all
select 3856,    16,     35.00,          0   union all
select 3857,    16,     6164.00,        0   union all
select 3858,    16,     9230.00,        0   union all
select 3859,    16,     22982.09,       0   union all
select 3860,    16,     7325.62,        0   union all
select 3861,    16,     4910.83,        0   union all
select 3862,    16,     5660.09,        0   union all
select 488,     18,     2079.00,        1   union all
select 489,     18,     1844.00,        1   union all
select 489,     18,     185.00,         1   union all
select 489,     18,     155.00,         1   union all
select 489,     18,     140.00,         1   union all
select 489,     18,     67.49,          1   union all
select 490,     18,     3925.00,        0   union all
select 490,     18,     7.54,           0   union all
select 490,     18,     150.00,         0   union all
select 490,     18,     150.00,         0   union all
select 490,     18,     60.00,          0   union all
select 491,     18,     1107.00,        1   union all
select 491,     18,     200.00,         1   union all
select 491,     18,     157.00,         1   union all
select 491,     18,     30.75,          1   union all
select 491,     18,     156.46,         1   union all
select 492,     18,     971.00,         1   union all
select 492,     18,     41.23,          1   union all
select 490,     18,     41.24,          0   union all
select 493,     18,     1614.00,        1   union all
select 492,     18,     20.00,          1   union all
select 490,     18,     20.00,          0   union all
select 494,     18,     1914.00,        0   union all
select 494,     18,     185.00,         0   union all
select 494,     18,     155.00,         0   union all
select 494,     18,     140.00,         1   union all
select 495,     18,     1777.00,        1   union all
select 495,     18,     65.94,          1   union all
select 495,     18,     245.00,         0   union all
select 495,     18,     230.00,         0   union all
select 495,     18,     157.47,         1   union all
select 495,     18,     70.18,          0   union all
select 494,     18,     67.49,          0   union all
select 496,     18,     163.00,         0   union all
select 496,     18,     250.00,         0   union all
select 496,     18,     2054.00,        0   union all
select 497,     18,     1457.00,        0   union all
select 497,     18,     163.00,         0   union all
select 497,     18,     130.00,         0   union all
select 495,     18,     20.00,          1   union all
select 495,     18,     9.99,           1;

-- ==================================================================================================

;WITH TotalData_CTE
AS
(
    SELECT JobNo, JobDate, DepartmentId, DepartmentName, CustomerName, FullPaid
    FROM @JobSImport job

    UNION
    
    SELECT JobNo, JobDate, DepartmentId, DepartmentName, CustomerName, FullPaid
    FROM @JobSeaExport job
    
    UNION
    
    SELECT JobNo, JobDate, DepartmentId, DepartmentName, CustomerName, FullPaid
    FROM @JobSeaClearance job

),
TotalCollectedInvocies
AS
(
    SELECT JobNo, job.DepartmentId, 
        ISNULL(SUM(m.S_Amount), 0) AS TotalCollected
    FROM TotalData_CTE job
        INNER JOIN @MainInvoices m ON m.JobId = job.JobNo AND m.DepartmentId = job.DepartmentId
    WHERE Paid = 1
    GROUP BY JobNo, job.DepartmentId
),
TotalPaidCosts
AS
(
    SELECT JobNo, job.DepartmentId, 
        ISNULL(SUM(cs.S_Amount), 0) AS TotalPaid
    FROM TotalData_CTE job
        INNER JOIN @CostSheet cs ON cs.JobId = job.JobNo AND cs.DepartmentId = job.DepartmentId
    WHERE Paid = 1
    GROUP BY JobNo, job.DepartmentId
    
)
SELECT TotalPaidCosts.JobNo, TotalPaidCosts.DepartmentId, 
    TotalCollected - TotalPaid AS TotalCollected
FROM TotalCollectedInvocies
    INNER JOIN TotalPaidCosts on TotalPaidCosts.JobNo = TotalCollectedInvocies.JobNo
        AND TotalPaidCosts.DepartmentId = TotalCollectedInvocies.DepartmentId
ORDER BY TotalPaidCosts.DepartmentId, TotalPaidCosts.JobNo
;

i don't know how to optimize CTE or if this is the best approach at first if someone kindly have different point of view, knowing this query did the job but it's too slow

thanks

that's the original query to display the following report:

ALTER PROCEDURE [dbo].[rp_DetailedProfitReport_V1]
    -- Add the parameters for the stored procedure here
    @DateFrom Date = NULL,
    @DateTo Date = NULL,
    @MemberId int = 0,
    @UserId int = 0,
    @SalesId int = 0,
    @DepartmentId int = 0,
    @DetailedJobs bit = 1,
    @PendingFullPaid int = 0

AS

BEGIN
    SET NOCOUNT ON;
;WITH TotalData_CTE
AS
(
    SELECT DISTINCT JobNo, JobDate, job.CustomerId, d.Id as DepartmentId, d.DepartmentName, m.CustomerName, FullPaid
    FROM JobSImport job
        INNER JOIN Departments d ON d.Id = job.DepartmentId
        INNER JOIN Customers m ON m.Id = job.CustomerId
    WHERE CanceledJob = 0
        AND closed = 0

    UNION
    
    SELECT DISTINCT JobNo, JobDate, job.CustomerId, d.Id as DepartmentId, d.DepartmentName, m.CustomerName, FullPaid
    FROM JobSeaExport job
        INNER JOIN Departments d ON d.Id = job.DepartmentId
        INNER JOIN Customers m ON m.Id = job.CustomerId
    WHERE CanceledJob = 0
        AND closed = 0
    
    UNION
    
    SELECT DISTINCT JobNo, JobDate, job.CustomerId, d.Id as DepartmentId, d.DepartmentName, m.CustomerName, FullPaid
    FROM JobSeaClearance job
        INNER JOIN Departments d ON d.Id = job.DepartmentId
        INNER JOIN Customers m ON m.Id = job.CustomerId
    WHERE CanceledJob = 0
        AND closed = 0

    UNION
    
    SELECT DISTINCT JobNo, JobDate, job.CustomerId, d.Id as DepartmentId, d.DepartmentName, m.CustomerName, FullPaid
    FROM JobAirImport job
        INNER JOIN Departments d ON d.Id = job.DepartmentId
        INNER JOIN Customers m ON m.Id = job.CustomerId
    WHERE CanceledJob = 0
        AND closed = 0

    UNION
    
    SELECT DISTINCT JobNo, JobDate, job.CustomerId, d.Id as DepartmentId, d.DepartmentName, m.CustomerName, FullPaid
    FROM JobAirExport job
        INNER JOIN Departments d ON d.Id = job.DepartmentId
        INNER JOIN Customers m ON m.Id = job.CustomerId
    WHERE CanceledJob = 0
        AND closed = 0

    UNION
    
    SELECT DISTINCT JobNo, JobDate, job.CustomerId, d.Id as DepartmentId, d.DepartmentName, m.CustomerName, FullPaid
    FROM JobAirClearance job
        INNER JOIN Departments d ON d.Id = job.DepartmentId
        INNER JOIN Customers m ON m.Id = job.CustomerId
    WHERE CanceledJob = 0
        AND closed = 0

    UNION
    
    SELECT DISTINCT JobNo, JobDate, job.CustomerId, d.Id as DepartmentId, d.DepartmentName, m.CustomerName, FullPaid
    FROM JobLandFreight job
        INNER JOIN Departments d ON d.Id = job.DepartmentId
        INNER JOIN Customers m ON m.Id = job.CustomerId
    WHERE CanceledJob = 0
        AND closed = 0

    UNION
    
    SELECT DISTINCT JobNo, JobDate, job.CustomerId, d.Id as DepartmentId, d.DepartmentName, m.CustomerName, FullPaid
    FROM JobWarehouse job
        INNER JOIN Departments d ON d.Id = job.DepartmentId
        INNER JOIN Customers m ON m.Id = job.CustomerId
    WHERE CanceledJob = 0
        AND closed = 0

), 
TotalInvocies_CTE
AS
(
    SELECT DISTINCT JobNo, job.DepartmentId, 
        SUM(ISNULL(m.S_Amount, 0)) AS TotalInvoices 
    FROM TotalData_CTE job
        LEFT JOIN MainInvoice m ON m.JobId = job.JobNo AND m.DepartmentId = job.DepartmentId
    WHERE m.DebitNote = 0
        AND m.CreditNote = 0 
    GROUP BY JobNo, job.DepartmentId
),
TotalPendingInvoices_CTE
AS
(
    SELECT DISTINCT JobNo, job.DepartmentId, 
        COUNT(ISNULL(m.InvoiceId, 0)) AS PendingInvoices
    FROM TotalData_CTE job
        LEFT JOIN MainInvoice m ON m.JobId = job.JobNo AND m.DepartmentId = job.DepartmentId
    WHERE m.Paid = 0
            -- AND m.DebitNote = 0
    GROUP BY JobNo, job.DepartmentId
),
TotalCosts_CTE
AS
(
    SELECT DISTINCT JobNo, job.DepartmentId, 
        SUM(ISNULL(c.S_TotalAmount, 0)) AS TotalCosts
    FROM TotalData_CTE job
        LEFT JOIN CostSheet c ON c.JobId = job.JobNo AND c.DepartmentId = job.DepartmentId
    WHERE c.Payment <> 14
    GROUP BY JobNo, job.DepartmentId
),
TotalPendingCosts_CTE
AS
(
    SELECT DISTINCT JobNo, job.DepartmentId, 
        COUNT(cs.Id) AS PendingCosts
    FROM TotalData_CTE job
        LEFT JOIN CostSheet cs ON cs.JobId = job.JobNo AND cs.DepartmentId = job.DepartmentId
    WHERE cs.Paid = 0
        AND Payment NOT IN (14, 16)
    GROUP BY JobNo, job.DepartmentId
),
TotalDebitNotesInvoices_CTE
AS
(
    SELECT DISTINCT JobNo, job.DepartmentId, 
        SUM(ISNULL(m.S_Amount, 0)) AS TotalDebitNotesInvoices
    FROM TotalData_CTE job
        LEFT JOIN MainInvoice m ON m.JobId = job.JobNo AND m.DepartmentId = job.DepartmentId
    WHERE m.Paid = 0
        AND m.DebitNote = 1
    GROUP BY JobNo, job.DepartmentId
), 
TotalCustomsCosts_CTE
AS
(
    SELECT DISTINCT JobNo, job.DepartmentId, 
        SUM(ISNULL(cs.S_TotalAmount, 0)) AS TotalCustomsCosts
    FROM TotalData_CTE job
        LEFT JOIN CostSheet cs ON cs.JobId = job.JobNo AND cs.DepartmentId = job.DepartmentId
    WHERE cs.Paid = 0
        AND Payment = 14
    GROUP BY JobNo, job.DepartmentId
),
TotalDopInvoices_CTE
AS
( 
    SELECT DISTINCT JobNo, job.DepartmentId, 
        CASE WHEN FullPaid = 0 THEN SUM(ISNULL(m.S_Amount, 0)) - SUM(ISNULL(m.TotalReceived, 0)) 
            ELSE SUM(ISNULL(m.S_Amount, 0)) - SUM(ISNULL(m.TotalReceived, 0)) END AS TotalDopInvoices
    FROM TotalData_CTE job
        LEFT JOIN MainInvoice m ON m.JobId = job.JobNo AND m.DepartmentId = job.DepartmentId
    WHERE m.Paid = 0
    
    GROUP BY JobNo, job.DepartmentId, FullPaid
),
TotalDOPCosts_CTE
AS
(
    SELECT DISTINCT JobNo, job.DepartmentId, 
        SUM(ISNULL(cs.S_TotalAmount, 0)) AS TotalDOPCosts
    FROM TotalData_CTE job
        INNER JOIN CostSheet cs ON cs.JobId = job.JobNo AND cs.DepartmentId = job.DepartmentId
    WHERE cs.Paid = 0
    GROUP BY JobNo, job.DepartmentId
),
TotalDopPartialCollectedNotPaid_CTE
AS
(
    SELECT DISTINCT job.JobNo, job.DepartmentId,
        ISNULL(inv.TotalReceived, 0) AS TotalPaid
    FROM TotalData_CTE job 
        INNER JOIN MainInvoice inv ON inv.JobID = job.JobNo and inv.DepartmentID = job.DepartmentID
        INNER JOIN CostSheet cs ON cs.JobID = job.JobNo and cs.DepartmentID = job.DepartmentID
    WHERE (ISNULL(INV.ReferenceId, 0) > 0)
        AND (FullPaid = 0 
            OR (inv.Paid = 0 AND inv.TotalReceived > 0 AND inv.TotalReceived < inv.F_Amount))
    GROUP BY job.JobNo, job.DepartmentId, inv.TotalReceived
    HAVING SUM(ISNULL(inv.TotalReceived, 0)) > 0
), 
TotalCreditNoteDopPaidNotCollected_CTE
AS
(
    SELECT DISTINCT job.JobNo, job.DepartmentId,
        CASE WHEN JobNo in (0) THEN 0 ELSE SUM(ISNULL(cs.S_TotalAmount, 0)) END AS TotalPaid
    FROM TotalData_CTE job 
        INNER JOIN MainInvoice inv ON inv.JobID = job.JobNo and inv.DepartmentID = job.DepartmentID
        INNER JOIN CostSheet cs ON cs.JobID = job.JobNo and cs.DepartmentID = job.DepartmentID
    WHERE cs.Paid = 1
        AND cs.Payment in (7)
        AND inv.Paid = 0
    GROUP BY job.JobNo, job.DepartmentId
),
TotalDopCollectedNotPaid_CTE
AS
(
    SELECT DISTINCT JobNo, job.DepartmentId, 
        SUM(ISNULL(cs.S_TotalAmount, 0)) AS TotalPaid
    FROM TotalData_CTE job
        INNER JOIN CostSheet cs ON cs.JobId = job.JobNo AND cs.DepartmentId = job.DepartmentId
    WHERE cs.Paid = 0
        AND cs.Payment not in (14, 16)
        AND FullPaid = 1
        AND ISNULL(ReferenceId, 0) = 0
    GROUP BY JobNo, job.DepartmentId
),
TotalDopPaidNotCollected_CTE
AS
(
    SELECT DISTINCT JobNo, job.DepartmentId, 
        SUM(ISNULL(cs.S_TotalAmount, 0)) AS TotalPaid
    FROM TotalData_CTE job
        INNER JOIN CostSheet cs ON cs.JobId = job.JobNo AND cs.DepartmentId = job.DepartmentId
    WHERE cs.Paid = 1
        AND cs.Payment not in (7, 14, 16)
        AND FullPaid = 0
        AND ISNULL(ReferenceId, 0) = 0

    GROUP BY JobNo, job.DepartmentId
)

SELECT job.JobNo, JobDate, job.CustomerId, job.DepartmentId, DepartmentName, CustomerName, 
        CASE WHEN PendingInvoices > 0 THEN ISNULL(TotalInvoices, 0) ELSE 0 END AS TotalInvoices, 
        ISNULL(PendingInvoices, 0) AS PendingInvoices,
        CASE WHEN PendingInvoices > 0 THEN ISNULL(TotalCosts, 0) ELSE 0 END AS TotalCosts, 
        ISNULL(PendingCosts, 0) AS PendingCosts,
        ISNULL(TotalDebitNotesInvoices, 0) AS TotalDebitNotesNotPaid,
        ISNULL(TotalCustomsCosts, 0) AS TotalCustomsNotesNotPaid,
        ISNULL(TotalDopInvoices, 0) AS TotalDopInvoices, 
        ISNULL(TotalDOPCosts, 0) AS TotalDOPCosts,
        ISNULL(tpcnp.TotalPaid, 0) AS TotalPartialCollectedNotPaid,
        ISNULL(tcnpnc.TotalPaid, 0) AS TotalDopPendingCreditNote,
        ISNULL(tcnp.TotalPaid, 0) AS TotalDopCollectedNotPaid,
        ISNULL(tpnc.TotalPaid, 0) AS TotalDopPaidNotCollected
        --
    FROM TotalData_CTE job
        INNER JOIN TotalInvocies_CTE inv ON job.JobNo = inv.JobNo AND job.DepartmentId = inv.DepartmentId
        INNER JOIN TotalCosts_CTE c ON job.JobNo = c.JobNo AND job.DepartmentId = c.DepartmentId
        LEFT JOIN TotalPendingInvoices_CTE tpinv ON job.JobNo = tpinv.JobNo AND job.DepartmentId = tpinv.DepartmentId
        LEFT JOIN TotalPendingCosts_CTE tpcs ON job.JobNo = tpcs.JobNo AND job.DepartmentId = tpcs.DepartmentId
        LEFT JOIN TotalDebitNotesInvoices_CTE tdni ON job.JobNo = tdni.JobNo AND job.DepartmentId = tdni.DepartmentId
        LEFT JOIN TotalCustomsCosts_CTE tcc ON job.JobNo = tcc.JobNo AND job.DepartmentId = tcc.DepartmentId
        LEFT JOIN TotalDopInvoices_CTE pInv ON job.JobNo = pInv.JobNo AND job.DepartmentId = pInv.DepartmentId
        LEFT JOIN TotalDOPCosts_CTE tdc ON job.JobNo = tdc.JobNo AND job.DepartmentId = tdc.DepartmentId
        LEFT JOIN TotalDopPartialCollectedNotPaid_CTE tpcnp ON job.JobNo = tpcnp.JobNo AND job.DepartmentId = tpcnp.DepartmentId
        LEFT JOIN TotalCreditNoteDopPaidNotCollected_CTE tcnpnc ON job.JobNo = tcnpnc.JobNo AND job.DepartmentId = tcnpnc.DepartmentId
        LEFT JOIN TotalDopCollectedNotPaid_CTE tcnp ON job.JobNo = tcnp.JobNo AND job.DepartmentId = tcnp.DepartmentId
        LEFT JOIN TotalDopPaidNotCollected_CTE tpnc ON job.JobNo = tpnc.JobNo AND job.DepartmentId = tpnc.DepartmentId

        --
WHERE (@PendingFullPaid = 2 OR (@PendingFullPaid = 0 AND (PendingInvoices > 0 OR PendingCosts > 0)))
        AND (@DateFrom IS NULL OR CAST(JobDate AS date) >= @DateFrom)
        AND (@DateTo IS NULL OR CAST(JobDate AS date) <= @DateTo)
        AND (@MemberId = 0 or CustomerId = @MemberId)
GROUP BY job.JobNo, JobDate, job.CustomerId, job.DepartmentId, DepartmentName, CustomerName,
        TotalInvoices, TotalCosts, PendingInvoices, PendingCosts, TotalDebitNotesInvoices, TotalCustomsCosts, 
        TotalDopInvoices, TotalDOPCosts, tpcnp.TotalPaid, tcnpnc.TotalPaid, tcnp.TotalPaid, tpnc.TotalPaid

ORDER BY JobNo, DepartmentName, JobDate DESC;

END

The output report showing all sections for the above Stored Procedure


Solution

  • At this point I have decided to write an answer, because otherwise you may get none.

    You have asked us to look at your query, because you

    • don't know whether it is optimal
    • don't even know whether it is correct

    In order to give the answers one must know the data. In the request comments I have tried to learn from you what the tables represent, what a job is and why there are separate tables that you must union. You have not been able to give an exhaustive explanation, and this may be the reason you have got no answer, yet.

    In your query the main task seems to be to get rid of duplicate data. This is a very costly task for a DBMS. And it is a task very rarely needed. When a professional database developer sees SELECT DISTINCT, alarm bells ring. There are occasions where this is appropriate, but those are few. Most often SELECT DISTINCT is just an indicator for a badly written query, or worse, a badly designed database. UNION [DISTINCT] instead of UNION ALL, too, is very often inappropriate. Often it is even only used because of obliviance to what it actually does and that UNION ALL would suffice to do the same task. In the request comments, however, you say that you do need all those DISTINCT and UNION [DISTINCT], so the key part in analyzing the query is to find out why.

    Your query is literally plastered with DISTINCT and UNION [DISTINCT]. Let's look at the easiest part first:

    SELECT DISTINCT JobNo, job.DepartmentId, 
        ISNULL(SUM(m.S_Amount), 0) AS TotalCollected
    FROM ...
    GROUP BY JobNo, job.DepartmentId
    

    You are aggregating data here, and with the GROUP BY clause, you tell the DBMS to return one result row per JobNo and DepartmentId. You select the two columns (and a sum), and then you apply DISTINCT. With one row per JobNo and DepartmentId and both columns in the list, how can there be possibly be any duplicates? It is just not possible. The DISTINCT is superfluous, and if the DBMS does not see through this, it will do unnecessary extra work.

    Now let's look at a part that is not as easy to judge:

    SELECT DISTINCT jobno, jobdate, customerid, departmentid, fullpaid
    FROM JobSImport
    

    This looks very suspicious. You have told us in the request comments, that you must apply DISTINCT here in order to remove duplicates. That means that the combination of jobno, jobdate, customerid, departmentid and fullpaid is not unique in the table. A jobid can occur multiple times, and its rows can have different dates and refer to different customers and departments. So, while you alias the table job, it is not containing jobs (with one row for a job number), but something else that you have failed to explain so far. In the request comments I guessed this may be a table of subjobs assigned to different customers and departments. That would explain the different dates, customers, departments and pay statuses for a single job.

    But this is a moment to pause for a moment ... Maybe, just maybe, the jobdate, customerid, departmentid don't really refer to a subjob (or whatever this is), but to the whole job. Maybe you know that DISTINCT will boil the rows down to one row per jobid (or jobid + departmentid, as this is the key you use later to join invoices and costs). If this is the case, then your data model is not normalized, and rather than thinking about how to write an optimal query, you should reconsider the database design. Database normalization is about properly storing the data in a database without redundancies (that bare the risk of data inconsistencies and also make it necessary to remove duplicate data in about every other query). Maybe you just need a main job table here to hold the job's jobdate once. Maybe you need a job-department table, containing information on who the department's single customer is for the job. I don't know. Only you can know the answer. If the concept of database normalization is new to you, learn it now and apply it to your database.

    If the database is normalized, and it is really just that you want to bundle the subjobs (or whatever they are) to get distinct combinations of jobno, jobdate, customerid, departmentid and fullpaid, then the question is: why this combination? In the request comments you say you need those UNION [DISTINCT] - again in order to remove duplicates. That means that the same combination of jobno, jobdate, customerid, departmentid and fullpaid can be found in different "job" tables. And we can ask again: why do you want to end up with unique rows for this combination? A possible result may look something like this:

    jobno jobdate customerid departmentid fullpaid
    1 2024-01-01 cus01 dep01 yes
    1 2024-01-02 cus01 dep01 no
    1 2024-01-01 cus02 dep01 no
    1 2024-01-03 cus02 dep02 no

    You call the CTE containing these rows TotalData_CTE and join it with your invoices and costs. Let's say your MainInvoice contains these rows:

    jobno departmentid s_amount paid
    1 dep01 1000 1
    1 dep02 2000 1

    This is your join:

    SELECT DISTINCT JobNo, job.DepartmentId, 
        ISNULL(SUM(m.S_Amount), 0) AS TotalCollected
    FROM TotalData_CTE job
        INNER JOIN MainInvoice m ON m.JobId = job.JobNo AND m.DepartmentId = job.DepartmentId
    WHERE Paid = 1
    GROUP BY JobNo, job.DepartmentId
    

    Let's first look at the joined rows before aggregation:

    jobno jobdate customerid departmentid fullpaid jobno departmentid s_amount paid
    1 2024-01-01 cus01 dep01 yes 1 dep01 1000 1
    1 2024-01-02 cus01 dep01 no 1 dep01 1000 1
    1 2024-01-01 cus02 dep01 no 1 dep01 1000 1
    1 2024-01-03 cus02 dep02 no 1 dep02 2000 1

    And now aggregated:

    jobno departmentid totalcollected
    1 dep01 3000
    1 dep02 2000

    You have multiplied the amount for departement dep01 by three, because there are three rows in the TotalData_CTE for jobno 1 and departementid dep01. This is probably not desired.

    So, however we look at this, either your data model is flawed or the query. My guess is: both. Get the data model fixed if it is really not normalized yet, then see which columns you really want to select in the TotalData_CTE to get proper aggregation results.