0

I have a stored procedure in Microsoft SQL Server. I want to combine multiple results into 1 row like this:

ID Period Income
202501_a 202501 50528.55

NOT LIKE THIS

ID Period Income
202501_a NULL NULL
Null 202501 NULL
NULL NULL 50528.55

The data and columns are for demonstration only, I understand you would not need a ID and a Period, you could use 1 column for both. It is just an example.

Selecting from table accounting_balance:

column type
period varchar(8)
credit decimal(20,2)
debit decimal(20,2)
account_no varchar(20)
--create temp table
--create a temp table with 3 columns.
IF (OBJECT_ID('tempdb..#financials') IS NOT NULL)
BEGIN
    DROP TABLE #financials
END

CREATE TABLE #financials
(
     id     VARCHAR(8),
     period VARCHAR(7),
     income DECIMAL(20, 2)
)

INSERT INTO #financials (id, period, income)
    --create the ids
    SELECT 
        CONCAT(period, '_a'), NULL, NULL
    FROM   
        accounting_balance
    WHERE  
        period LIKE '2025%'
    UNION ALL
    --get 1st column
    SELECT 
        NULL, period, NULL
    FROM   
        accounting_balance
    WHERE  
        period LIKE '2025%'
    UNION ALL
    -- get 2nd column
    SELECT 
        NULL, NULL, ABS(SUM(credit - debit))
    FROM   
        accounting_balance
    WHERE  
        account_no = '4000-001-01'

-- display temp table data
SELECT *
FROM #financials 

-- drop the table
DROP TABLE #financials 

A table showing sample results

8
  • 3
    What exactly is the question here? Also why do you need the #financials temp table, why not just run the unioned SELECT by itself? Also why is period a varchar column and not a date column? Commented Oct 28 at 13:28
  • I want the output in 1 row, not 3. The temp table is used to build a screen in an application. Is period being a varchar affecting the results? Commented Oct 28 at 13:50
  • No, no, no, you don't want to UNION at all. Once you have unioned, you will need to re-merge (let's say with a self join of your UNION-generated table). Then how would you tell which row to join to which row? Of course you could tell it to put 1 non-null column 1 with first non-null column 2 with first non-null column 3 (and so on for second, third, etc., thanks to window functions) but this would be very fragile. So do it in 1 query where columns are related to the same row from the beginning. Commented Oct 28 at 13:57
  • 1
    Please don't use images, use table markdown (as you have earlier) Commented Oct 28 at 14:09
  • 1
    Please don't post the same question again stackoverflow.com/staging-ground/79802744 Commented Oct 28 at 14:21

1 Answer 1

1

One row per period for the given account_no when it has data

As explained in the comments, your RDBMS is naturally built to do aggregates thanks to the GROUP BY keyword. So GROUP BY period so that one row is output (with the Sum() of matching rows) per different period, as intended:

INSERT INTO #financials
SELECT Concat(period, '_a'),
       period,
       Coalesce(Sum(credit), 0) - Coalesce(Sum(debit), 0)
FROM   accounting_balance
WHERE  period LIKE '2025%'
AND    account_no = '4000-001-01'
GROUP BY period;
id period income
202501_a 202501 50528.55
202502_a 202502 601475.70

One row per period, filtering data only for a given account_no

If you want to output every period, even those where account 4000-001-01 has now debit nor credit, but limit the income to those for this account, instead of filtering on the whole query (in the global WHERE) you'll use a conditional aggregate: Sum(CASE WHEN account_no = '4000-001-01' THEN credit END).
Then only debit and credit of rows for account 4000-001-01 will be accounted for.

INSERT INTO #financials
SELECT Concat(period, '_a'),
       period,
       Sum(CASE WHEN account_no = '4000-001-01' THEN Coalesce(credit, 0) - Coalesce(debit, 0) END)
FROM   accounting_balance
WHERE  period LIKE '2025%'
GROUP BY period;

For example, if 4000-001-01 has only balance in January and February but not in March, you'll get:

id period income
202501_a 202501 50528.55
202502_a 202502 601475.70
202503_a 202503 null

(everything is shown in a db<>fiddle)

Risky cut and paste

… OK, if you only want to paste columns of unrelated tables next to each other, you'll have to ask each row its position thanks to the row_number() window function, and join on matching positions.
You'll probably get totally unexpected results as some rowsets will have less entries than others, but that's the result of trying to use an RDBMS (with an R as "Relational") to do spreadsheet-like works over unRelated data.

WITH
--create the ids
t1 AS
(
SELECT Concat(period, '_a') id,
       row_number() over (order by period) as pos
FROM   accounting_balance
WHERE  period LIKE '2025%'
),
--get 1st column
t2 AS
(
SELECT period,
       row_number() over (order by period) as pos
FROM   accounting_balance
WHERE  period LIKE '2025%'
),
--get 2nd column
t3 AS
(
SELECT Abs(Sum(Coalesce(credit, 0) - Coalesce(debit, 0))) income,
       row_number() over (order by period) as pos
FROM   accounting_balance
WHERE  account_no = '4000-001-01'
GROUP BY period
)
INSERT INTO #financials
            (id,
             period,
             income)
SELECT id, period, income
FROM t1
JOIN t2 ON t2.pos = t1.pos
JOIN t3 ON t3.pos = t1.pos
;
id period income
202501_a 202501 50528.55
202501_a 202501 601475.70

Wait… 202501 for both rows? Yes, because I had multiple rows for January in my example table, so t1 and t2 started with 3 rows in January, while the matching rows in t3 (the aggregated table for sums by month) gave 1 row per month. So now for row 2 of the 3 tables you've got February's total amount associated with the second row from accounting_balance, which happens to be in January.

(show as last query in the augmented fiddle)

Sign up to request clarification or add additional context in comments.

1 Comment

Awesome, Worked like a charm, thank-you.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.