CASE expression sum - issue when joining to other tables - sql

I have a case expression in a stored procedure summing an account field, and then inserting into a user id. The logic works... until joining to another table.
I tried adding distinct counts, and additional tables to the query, but still when I join to another table it applies the 1 value when I want it to be 0 to the account.
This is the calculation in the stored proc;
INSERT INTO #SUMMARY_TEMP (USER_ID,FSN_CNT )
(SELECT USER_ID,
SUM(CASE WHEN A_GROUP_CD = 'RED' AND A_TYPE_CD = 'FSN' THEN REC_COUNT ELSE 0 END)
) AS 'FSN_CNT',
FROM (SELECT A_ACCOUNT_NBR,
A_USER_ID,
A_GROUP_CD,
A_TYPE_CD,
COUNT(*) AS REC_COUNT
FROM EXCEPTION_DETAIL
INNER JOIN #STAFF ON A_REPORT_DT = #REPORT_DT
AND (A_USER = B_USER_ID)
GROUP BY A_ACCOUNT_NBR,
A_USER_ID_ID,
A_GROUP_CD,
A_TYPE_CD) EXCEPTIONS
GROUP BY A_USER_ID,
A_ACCOUNT_NBR)
This is the result which is what I expect for 2 USER Ids
A_ACCOUNT_NBR USER_ID FSN_CNT
123456 HENRY 0
123498 HENRY 1
374933 JOE 1
474930 JOE 0
but when I join to another table the data looks like
A_ACCOUNT_NBR USER_ID FSN_CNT
123456 HENRY 1
123498 HENRY 1
374933 JOE 1
474930 JOE 1
Its applying the 1 value to account 123456 & 474930 when it should be 0.
I think its because the other table does not have the ACCOUNT_NBR column - I am joining on USER_ID and so it applies the 1 to all ACCOUNT_NBR from table A.
Thanks for all the suggestions, I tried using a CTE, and the counts now look good, but its created duplicate rows as shown below. Any suggestions on how to remove the duplication, below is the join I am using for the CTE;
select cte.*, jt.USER_ID
from cte
join EXCEPTION_DETAIL jt on cte.USER_ID=jt.USER_ID
USER ACCOUNT_NBR FSN_CNT
HENRY 123456 0
HENRY 123456 0
HENRY 123498 1
HENRY 123498 1
JOE 374933 1
JOE 374933 1
JOE 474930 0
JOE 474930 0

you can separate the 1st query by using cte and join with it next level like below
with cte as
(
(SELECT USER_ID,
SUM(CASE WHEN A_GROUP_CD = 'RED' AND A_TYPE_CD = 'FSN' THEN REC_COUNT ELSE 0 END)
) AS 'FSN_CNT',
FROM (SELECT A_ACCOUNT_NBR,
A_USER_ID,
A_GROUP_CD,
A_TYPE_CD,
COUNT(*) AS REC_COUNT
FROM EXCEPTION_DETAIL
INNER JOIN #STAFF ON A_REPORT_DT = #REPORT_DT
AND (A_USER = B_USER_ID)
GROUP BY A_ACCOUNT_NBR,
A_USER_ID_ID,
A_GROUP_CD,
A_TYPE_CD) EXCEPTIONS
GROUP BY A_USER_ID,
A_ACCOUNT_NBR)
) select cte.*,jt.USER_ID from cte join jointable_name jt on cte.USER_ID=jt.USER_ID

Related

Find rows in which a column value only occurs once (Single-Sided Entries in Double Entry accounting system)

I have a table of bank transactions, AccountTransaction, and rows with for e.g.
Amount
Payee_Name
Transaction_ID
Is_Corresponding_Transaction
69.00
Bob Jones
1
1
-69.00
Bob Jones
1
0
25.00
Bill
2
1
-25.00
Bill
2
0
297.00
Sally
3
1
-5.00
Ted
4
1
2.50
Ted
4
0
2.50
Ted
4
0
How do I select only (all) TS like Sally's where the Transaction ID only occurs once?
Bonus points: How do I select TS like Ted's where the sum of all Is_Corresponding_Transaction = 0 != the sum of Is_Corresponding_Transaction = 1 for a given TS_ID?
I was looking and found a Group by or where not exists, but couldn't figure out how to get that to work
Here's an e.g. of what I tried:
select
Full_Name, amount, a.Posted_Date,a.Payee_Name, a.Memo, Accounts.Account_Name
from AccountTransaction a
left join Accounts on Accounts.Account_Code = a.Account_Code
left join users on a.UserId = users.UserId
where not exists (select 1 from AccountTransaction b where a.Transaction_ID = b.Transaction_ID having count(*)>1)
and a.Pending= 0
ORDER by a.Posted_Date desc
Just to expand on Stu's comment. Here is one option that uses the window function
with cte as (
Select *
,NetSum = sum(Amount) over (partition by Transaction_ID)
,NetCnt = sum(1) over (partition by Transaction_ID)
From YourTable
)
Select *
From cte
Where NetSum<>0
or NetCnt<>2

SQL help i need to find the inventory remaining in my office

In sql help i have 3 tables, table one is asset table which is as follow
id
asset_code
asset_name
asset_group
asset_quantity
1
A001
demo asset
4
5
2
A002
demo asset 2
6
3
and another table is asset_allocation
id
asset_id
allocated_quantity
allocated_location
1
1
2
IT office
2
1
1
main hall
the last table is asset_liquidated which will present assets that are no longer going to be used
id
asset_id
liquidated_quantity
1
1
2
2
1
1
lets say i have 5 computers and i have allocated 3 computers and 1 is no longer going to be used so i should be remaining with 1 computer so now how do i make sql auto generate this math for me
You need to use aggregation and the join your tables -
SELECT id, asset_code, asset_name, asset_group, asset_quantity,
asset_quantity - COALESCE(AA.allocated_quantity, 0) - COALESCE(AL.liquidated_quantity, 0) available_quantity
FROM asset A
LEFT JOIN (SELECT asset_id, SUM(allocated_quantity) allocated_quantity
FROM asset_allocation
GROUP BY asset_id) AA ON A.id = AA.asset_id
LEFT JOIN (SELECT asset_id, SUM(liquidated_quantity) liquidated_quantity
FROM asset_liquidated
GROUP BY asset_id) AL ON A.id = AL.asset_id
This query will give you -1 as available_quantity for asset_id 1 as you have only 5 available, 3 of them are allotted and 3 are liquidated as per your sample data.
Please see if this helps
SELECT
asset_quantity AS Total_Assets
,ISNULL(allocated_quantity, 0) allocated_quantity
,ISNULL(liquidated_quantity, 0) liquidated_quantity
FROM asset
LEFT OUTER JOIN (
SELECT
asset_id, SUM(allocated_quantity) AS allocated_quantity
FROM asset_allocation
GROUP BY asset_id
) asset_allocation2
ON asset_allocation2.asset_id = asset.id
LEFT OUTER JOIN (
SELECT
asset_id, SUM(liquidated_quantity) AS liquidated_quantity
FROM asset_liquidated
GROUP BY asset_id
) asset_liquidated 2
ON asset_liquidated 2.asset_id = asset.id

Select count of total records and also distinct records

I have a table such as this:
PalmId | UserId | CreatedDate
1 | 1 | 2018-03-08 14:18:27.077
1 | 2 | 2018-03-08 14:18:27.077
1 | 3 | 2018-03-08 14:18:27.077
1 | 1 | 2018-03-08 14:18:27.077
I wish to know how many dates were created for Palm 1 and I also wish to know how many users have created those dates for Palm 1. So the outcome for first is 4 and outcome for second is 3
I am wondering if I can do that in a single query as oppose to having to do a subquery and a join on itself as in example below.
SELECT MT.[PalmId], COUNT(*) AS TotalDates, T1.[TotalUsers]
FROM [MyTable] MT
LEFT OUTER JOIN (
SELECT MT2.[PalmId], COUNT(*) AS TotalUsers
FROM [MyTable] MT2
GROUP BY MT2.[UserId]
) T1 ON T1.[PalmId] = MT.[PalmId]
GROUP BY MT.[PalmId], T1.[TotalUsers]
According to first table you could do something like this:
select count(distinct uerid) as N_Users,
count(created_date) as created_date, -- if you use count(*) you consider also rows with 'NULL'
palmid
from your_table
group by palmid
If you want "4" and "3", then I think you want:
SELECT MT.PalmId, COUNT(*) AS NumRows, COUNT(DISTINCT mt.UserId) as NumUsers
FROM MyTable MT
GROUP BY MT.PalmId

T-SQL (Azure) Only shows 2 results instead of 3

Hi i am extending a query and i have the following problem, i have in a table 3 users and they are connected (joined) with other tables, now in these tables the user can or can not have data, depending on their actions.
SELECT
COALESCE (credit.received, 0) AS CreditReceived,
COALESCE (purchase.used, 0) AS CreditUsed,
COALESCE (purchase.NumberOfPurchase, 0) AS NumberOfPurchase,
COALESCE (credit.received, 0) - COALESCE (purchase.used, 0) AS UserCredit,
dbo.[User].id_user,
dbo.[User].name,
dbo.[User].town,
dbo.[User].country
FROM (SELECT DISTINCT id_user
FROM dbo.UserCredit
UNION
SELECT DISTINCT id_user
FROM dbo.UserPurchase) AS users
INNER JOIN
dbo.[User] ON users.id_user = dbo.[User].id_user
LEFT OUTER JOIN
(SELECT
id_user,
SUM(creditRecieved) AS received
FROM
dbo.UserCredit AS UserCredit_1
GROUP BY id_user) AS credit
ON users.id_user = credit.id_user
LEFT OUTER JOIN
(SELECT
id_user,
SUM(creditUsed) AS used,
COUNT(creditUsed) AS NumberOfPurchase
FROM
dbo.UserPurchase AS UserPurchase_1
GROUP BY id_user) AS purchase
ON users.id_user = purchase.id_user
The information comes from these tables;
TABLE dbo.user
id_user name town country
----------- ----------- -------------- -------------
1 George New York USA
2 Lucas San Diego GB
3 Steven San Fran Germany
TABLE dbo.UserCredit
id id_user creditRecieved PurchasePrice
----------- ----------- -------------- -------------
1 1 150 750
2 1 25 100
3 2 65 15
TABLE dbo.UserPurchase
id id_user creditUsed date
----------- ----------- ----------- -----------
1 1 175 NULL
2 2 3 NULL
3 2 2 NULL
What i get is only the result of the two first user_id's and the third one (steven) is not shown in the results, i guess it is because the id's dont exist in the other two tables, but that i was hoping would be fixed with the COALESCE and the four of them would be set to 0. What am i doing wrong?
You don't need the derived table "users." It doesn't contain all the userid's and is unnecessary. Remove that and left join to your user table instead and it should work.
By replacing the first DISTINCT with the dbo.[User] instead of the dbo.UserCredit it gave me the right results; All users in the overview with credit or no credit, thanks to the COALESCE :)
SELECT
COALESCE (credit.received, 0) AS CreditReceived,
COALESCE (purchase.used, 0) AS CreditUsed,
COALESCE (purchase.NumberOfPurchase, 0) AS NumberOfPurchase,
COALESCE (credit.received, 0) - COALESCE (purchase.used, 0) AS UserCredit,
dbo.[User].id_user,
dbo.[User].name,
dbo.[User].town,
dbo.[User].country
FROM (SELECT DISTINCT id_user
FROM dbo.[User]
UNION
SELECT DISTINCT id_user
FROM dbo.UserPurchase) AS users
INNER JOIN
dbo.[User] ON users.id_user = dbo.[User].id_user
LEFT OUTER JOIN
(SELECT
id_user,
SUM(creditRecieved) AS received
FROM
dbo.UserCredit AS UserCredit_1
GROUP BY id_user) AS credit
ON users.id_user = credit.id_user
LEFT OUTER JOIN
(SELECT
id_user,
SUM(creditUsed) AS used,
COUNT(creditUsed) AS NumberOfPurchase
FROM
dbo.UserPurchase AS UserPurchase_1
GROUP BY id_user) AS purchase
ON users.id_user = purchase.id_user

SQL Select Master Records and Display Number of Detail Records for Each

I have a Master and Detail table, the Detail linking to the Master record on a FK reference.
I need to display all the data from the Master table, and the corresponding number of details for each record, i.e.
MASTER TABLE
ID Name Age
1 John 15
2 Jane 14
3 Joe 15
DETAIL
MasterID Subjects
1 Trigonometry
1 Chemistry
1 Physics
1 History
2 Trigonometry
2 Physics
Thus, when I ran the SQL statement, I would have the following result:
ID Name Age #Subjects
1 John 15 4
2 Jane 14 2
3 Joe 15 0
Thanks!
This may be useful
SELECT mt.ID, mt.NAME, mt.AGE, COUNT(d.MasterID) as [#Subjects]
FROM MasterTable mt
LEFT OUTER JOIN Detail d on mt.ID = d.ID
GROUP BY mt.ID, mt.NAME, mt.AGE
ORDER BY mt.ID
select id,
name,
age,
( select count(*)
from detail
where master.id = detail.id ) as record_count
from master
syntax adjusted depending on what db you are using