how to write the select statement in case statement - sql-server-2008

Let me know how to write select query in case statement.
select
ROW_NUMBER() OVER(Order by vendor.VendorName ) AS ID,
PH.PurchasingHeaderID as BILLNo,
PH.TotalPriceCompanyCurrency as Balance,
acc.AccountName as [Account_Name]
**Into #tempOpenVedorlist**
from PurchasingHeader PH
LEFT OUTER JOIN TransactionType Trans ON PH.TransactionTypeID =Trans.TransactionTypeID
LEFT OUTER JOIN Vendor vendor on PH.VendorID=vendor.VendorID
LEFT OUTER JOIN PaymentTerm PT on PT.PaymentTermID = vendor.PaymentTermID
LEFT OUTER JOIN PurchasingDetail PD on PD.PurchasingHeaderID = PH.PurchasingHeaderI
LEFT OUTER JOIN Account Acc on Acc.AccountID= PD.FinancialAccountID
where PH.TransactionTypeID=7
Group by vendor.VendorName,
PH.PurchasingHeaderID,PH.TotalPriceCompanyCurrency,acc.AccountName
I GOT THIS RESULT :
with this result: Here i have No : VB1003 two times but Account Name is different.
ID BILLNo Account_Name Balance
-------------------------------------------------------------
101 VB1000 Cash-Petty Cash 4000.00
102 VB1001 Accounts Receivable 5000.00
103 VB1003 Cash-PettyCash 6000.00
104 VB1003 Cash 6000.00
105 VB1004 UndepositedFunds 7000.00
Here i have to show ;
I need this result :
ID BILLNo Account_Name Balance
------------------------------------------------------
101 VB1000 Cash-PettyCash 4000.00
102 VB1001 AccountsReceivable 5000.00
103 VB1003 ---Multiple---- 6000.00
104 VB1004 UndepositedFunds 7000.00
For aboue result what i have did : i have taken all the data in temp table.
Am able show Multiple string for which has more than one No.
But unfortunatly am not able show Account Name for which has only one BILLNo.
select ROW_NUMBER() OVER(Order by BILLNo ) AS ID,
[BILLNo],
Balance,
CASE
WHEN count(BILLNo)>1 THEN 'Multipul'
WHEN count(BILLNo)<2 THEN **(Select Account_Name from #tempOpenVedorlist )**
End As [Financial_Account]
from #tempOpenVedorlist
Group By BILLNo,Balance
Let me know how can i get account name from temp table which is related to that BILLNo.

Remove the AccountName from the GROUP BY and put an aggregate on that.
SELECT ROW_NUMBER() OVER(Order by vendor.VendorName ) AS ID,
PH.PurchasingHeaderID as BILLNo,
PH.TotalPriceCompanyCurrency as Balance,
CASE WHEN MIN(acc.AccountName) IS NULL
THEN '----'
WHEN MIN(acc.AccountName) = MAX(acc.AccountName)
THEN MIN(acc.AccountName)
ELSE '--MULTIPLE--'
END as [Account_Name]
INTO #tempOpenVedorlist
FROM PurchasingHeader PH
LEFT OUTER JOIN TransactionType Trans
ON PH.TransactionTypeID =Trans.TransactionTypeID
LEFT OUTER JOIN Vendor vendor
ON PH.VendorID=vendor.VendorID
LEFT OUTER JOIN PaymentTerm PT
ON PT.PaymentTermID = vendor.PaymentTermID
LEFT OUTER JOIN PurchasingDetail PD
ON PD.PurchasingHeaderID = PH.PurchasingHeaderI
LEFT OUTER JOIN Account Acc
ON Acc.AccountID= PD.FinancialAccountID
WHERE PH.TransactionTypeID=7
GROUP BY vendor.VendorName,
PH.PurchasingHeaderID,
PH.TotalPriceCompanyCurrency

Related

Join three tables and subtract sum of column from a column data

I have three tables accounts, receivables and receiveds .
My basic table is receivables I want to get the names from the account table and then subtract the sum of received column in receiveds table form the receivable column in receivables table with same ref numbers. i want to ignore if the balance is zero.
accounts
id
name
22
John
23
Kahn
24
Falis
25
Haseni
26
Gent
receivables
id
receivable
Ref
22
70
A1
24
100
A2
26
60
A3
24
15
A4
receiveds
ref
id
received
A1
22
30
A2
24
60
A1
22
40
A3
26
20
A2
24
10
desired results
id
name
ref
receivable
received
balance
total_id_balance
24
Falis
A2
100
70
30
45
26
Gent
A3
60
20
40
40
24
Falis
A4
15
0
15
45
I have tried this code but it's not working for me
SELECT *
FROM receivables AS rvb
LEFT JOIN accounts AS acc
ON rvb.id = acc.id
LEFT JOIN (SELECT SUM(received) as sum_rvd FROM receiveds) AS rvd
ON acc.id = rvd.id where rvb.receivable>rvd.sum_rvd
INNER JOINs filter out NULL values and the HAVING clause removes zero-balance rows.
SELECT
accounts.* ,
ra.receivable,
rd.received,
ra.receivable - rd.received as balance
FROM accounts
INNER JOIN ( SELECT id, SUM(receivable) as receivable FROM receivables GROUP BY id ) ra
ON ra.id = accounts.id
INNER JOIN ( SELECT id, SUM(received) as received FROM receiveds GROUP BY id ) rd
ON rd.id = accounts.id
HAVING balance > 0
UPDATE
With a ref field we just need to add it as another grouping field for subselects, and change second INNER JOIN to LEFT JOIN (actually looks like it was a mistake from the start, coz we missed entries without receiveds that still had positive balance). Also changing received field to a COALESCE to get zeroes instead of NULL's (indicating non existing rows in a receiveds table).
Since you need an overall per-id total_id_balance field, the natural way to grab it - is using window functions. Note, they are supported only for MySQL 8.0+.
So the resulting query looks like this:
SELECT
accounts.* ,
ra.ref,
ra.receivable,
COALESCE(rd.received, 0) as received,
ra.receivable - COALESCE(rd.received, 0) as balance,
SUM( ra.receivable - COALESCE(rd.received, 0) ) OVER ( PARTITION BY id ) as total_id_balance
FROM accounts
INNER JOIN ( SELECT id, SUM(receivable) as receivable, ref FROM receivables GROUP BY id, ref ) ra
ON ra.id = accounts.id
LEFT JOIN ( SELECT id, SUM(received) as received, ref FROM receiveds GROUP BY id, ref ) rd
ON
rd.id = accounts.id
AND
ra.ref = rd.ref
HAVING balance > 0
ORDER BY ref
This work for me -
EDIT-
Add support for non-unique id in receivables
SELECT acc.id ,acc.name, res.receivable, res.received, (res.receivable - res.received) AS balance
FROM accounts AS acc JOIN
(SELECT recv.id, recv.receivable, rec.received
FROM (
SELECT id, SUM(receivable) AS receivable
FROM receivables
GROUP BY id) AS recv JOIN
(SELECT id, SUM(received) AS received
FROM receiveds
GROUP BY id) AS rec ON rec.id = recv.id
WHERE rec.received < recv.receivable) AS res ON res.id = acc.id;
Assuming it is possible to have an id in receivables without a corresponding id in receiveds, the second join needs to be a LEFT JOIN and you need to handle the NULLs in your SELECT list -
SELECT
a.*,
ra.receivable,
IFNULL(rd.received, 0) received,
ra.receivable - IFNULL(rd.received, 0) balance
FROM accounts a
INNER JOIN (
SELECT id, SUM(receivable) receivable
FROM receivables
GROUP BY id
) ra
ON a.id = ra.id
LEFT JOIN (
SELECT id, SUM(received) received
FROM receiveds
GROUP BY id
) rd
ON a.id = rd.id
HAVING balance > 0;
You can (and should) go a step further and remove the first derived table as it is unnecessary overhead -
SELECT
a.*,
SUM(ra.receivable) receivable,
IFNULL(SUM(rd.received), 0) received,
SUM(ra.receivable) - IFNULL(rd.received, 0) balance
FROM accounts a
INNER JOIN receivables ra
ON a.id = ra.id
LEFT JOIN (
SELECT id, SUM(received) received
FROM receiveds
GROUP BY id
) rd
ON a.id = rd.id
GROUP BY id
HAVING balance > 0;
db<>fiddle

How to return customers and additional info who have null in second table

T1 Customers
IDZ NAME MEGAID
123 TOM 32132
124 JEK 32323
125 MAX 32342
126 JIZ 32134
T2 Info:
ID CID GUNS STATUS
1 123 3 1
2 124 4 2
3 126 NULL 1
T3 Status:
ID TYPE
1 Active
2 Inactive
IDZ = CID
I need to return NAME, MEGAID and STATUS (Active/Inactive) for everyone who have NULL on GUNS column from INFO table.
I tried this:
SELECT Customers.Name, CustomersMEGAID, Status.TYPE
FROM Customers
LEFT JOIN Customers ON Info.CID=Custoners.IDZ
WHERE Info.Guns= IS NULL;
But thats doesnt work(
Big thanks if someone can help with this
your question is full with errors but here is a query for you:
SELECT Customers.Name, Customers.MEGAID, Status.TYPE
FROM Customers
LEFT JOIN Info ON Customers.IDZ = Info.CID
INNER JOIN Status ON Info.STATUS = Status.ID
WHERE Info.Guns IS NULL;
You can join all three tables, and then search for nulls in the column.
For example:
select
c.name,
c.megaid,
s.type
from customers c
join info i on i.cid = c.idz
join status s on s.id = i.status
where i.guns is null

mysql sum() return double value using multiple joins

select
a.ClientID,
f.Currency,
a.OrganizationName,
COALESCE(sum(b.GrandTotal),0) as SaleGrandTotal,
COALESCE(sum(g.AmountReceived),0) as AmountReceived,
COALESCE(sum(b.GrandTotal - g.AmountReceived),0) as SaleBalanceRemaining,
COALESCE(sum(d.GrandTotal), 0) as PurchaseGrandTotal,
COALESCE(sum(e.AmountPaid), 0) as AmountPaid,
COALESCE(sum(d.GrandTotal - e.AmountPaid),0) as PurchaseBalanceRemaining,
COALESCE(sum(b.GrandTotal - g.AmountReceived),0) - COALESCE(sum(d.GrandTotal - e.AmountPaid),0) as Total
from na_clients as a
join na_currency as f
left join na_transaction as b
on a.ClientID = b.ClientID and b.CurrencyID = f.CurrencyID and b.IsActive = 1
left join na_recoverylogs as g
on b.TID = g.TID
left join na_purchase as d
on a.ClientID = d.ClientID and d.CurrencyID = f.CurrencyID and d.IsActive = 1
left join na_purchaselogs as e
on e.PID = d.PID
group by a.OrganizationName,f.Currency
order by a.OrganizationName
I am using multiple currency like dollar,CNY,rupees.
It was working fine but today i noticed sum() double value like b.GrandTotal should be 11500 but its return 23000
Table Client:
clientid,name,organizationName
1,client1,OrgName
2,client2,OrgName
Table Currency:
currencyid,cname
1,Dollar
2,Rupees
Table Transaction:
tid,clientid,currencyid,grandTotal,amountReceived,balanceremaining
1,1,1,11000,0,11000
2,1,1,500,0,500
Table recoveryLogs: // Another Error Here
id,tid,amountreceived
1,1,0
2,2,0
3,2,2000 // Again sum() multiply value - because of PID 2 is repeating
Table Purchase:
pid,clientid,currencyid,grandTotal,amountPaid,balanceRemaining
1,1,1,25000,0,25000
1,2,2,2,3000,1000,2000
Now I am using sum(b.grandTotal) instead of 11500 it return 23000
Table PurchaseLogs: // Another Error Here
id,pid,amountpaid
1,1,0
2,2,1000
3,1,1000 // Again sum() multiply value - because of PID 1 is repeating
So result should be:
Client: Client1
SaleGrandTotal: 11500
AmountReceived: 0
SaleBalanceRemaining: 11500
PurchaseGrandTotal: 25000
AmountPaid: 0
PurchaseBalanceRemaining: 25000
Total Amount: -13500
But result i get:
Client: Client1
SaleGrandTotal: 23000
AmountReceived: 0
SaleBalanceRemaining: 23000
PurchaseGrandTotal: 50000
AmountPaid: 0
PurchaseBalanceRemaining: 50000
Total Amount: -27000
If i remove purchase clause(d and e) or transaction(b and g) clause from query it's working fine individually.
The reason data is doubling is your ClientID has different occurrences in Transaction and Purchase tables and hence not a 1-to-1 match. ClientID = 1 and CurrencyID = 1 appears twice in Transaction and only once in Purchase. When you join the tables, a combination set of 1 x 2 = 2 ClientID records result with some fields repeating data. Thus, summing will double for repeat entries. As illustration:
Transaction Data | Purchase Data
row1: 1,1,1,11000,0,11000 | 1,1,1,25000,0,25000
row2: 2,1,1,500,0,500 | 1,1,1,25000,0,25000
Consider separating the aggregation between both tables using derived tables. Then, join the four underlying aggregates (transaction, purchase, recovery log, purchase log) for final query. The join will match 1-to-1 if you aggregate, grouping on ClientID and CurrencyID, TID and PID.
SELECT
transAgg.ClientID, transAgg.Currency, transAgg.OrganizationName,
transAgg.SaleGrandTotal, recovLogAgg.SumOfAmtReceived,
(transAgg.SaleGrandTotal - recovLogAgg.SumOfAmtReceived) as SaleBalanceRemaining,
purchAgg.PurchaseGrandTotal, purchLogAgg.SumOfAmtPaid,
(purchAgg.PurchaseGrandTotal - purchLogAgg.SumOfAmtPaid) as PurchaseBalanceRemaining,
((transAgg.SaleGrandTotal - recovLogAgg.SumOfAmtReceived) -
(purchAgg.PurchaseGrandTotal - purchLogAgg.SumOfAmtPaid)) As [Total]
FROM
(SELECT
a.ClientID, f.CurrencyID, f.Currency, a.OrganizationName,
COALESCE(sum(b.GrandTotal),0) as SaleGrandTotal
FROM na_clients as a
INNER JOIN na_currency as f
LEFT JOIN na_transaction as b
ON a.ClientID = b.ClientID
AND b.CurrencyID = f.CurrencyID
AND b.IsActive = 1
GROUP BY a.ClientID, a.OrganizationName, f.CurrencyID, f.Currency
ORDER BY a.OrganizationName) As transAgg
INNER JOIN
(SELECT
a.ClientID, f.CurrencyID, f.Currency, a.OrganizationName,
COALESCE(sum(d.GrandTotal), 0) as PurchaseGrandTotal
FROM na_clients as a
INNER JOIN na_currency as f
LEFT JOIN na_purchase as d
ON a.ClientID = d.ClientID
AND d.CurrencyID = f.CurrencyID
AND d.IsActive = 1
GROUP BY a.ClientID, a.OrganizationName, f.CurrencyID, f.Currency
ORDER BY a.OrganizationName) As purchAgg
ON transAgg.ClientID = purchAgg.ClientID
AND transAgg.CurrencyID = purchAgg.CurrencyID
INNER JOIN
(SELECT
g.TID, COALESCE(sum(g.AmountReceived),0) As SumOfAmtReceived
FROM na_recoverylogs as g
GROUP BY g.TID) As recovlogAgg
ON transAgg.TID = recovlogAgg.TID
INNER JOIN
(SELECT
e.PID, COALESCE(sum(e.AmountPaid),0) As SumOfAmtPaid
FROM na_purchaselogs as e
GROUP BY e.PID) As purchlogAgg
ON purchAgg.PID = purchlogAgg.PID

How to use cross join with left outer join?

I have to show list of employee who has claim for expense for the particular month, but am getting all employee list.
SELECT employee_id, expense_month, GROUP_CONCAT(CONCAT_WS('=', exp_type_text, monthly_exployee_expense))
FROM
(
SELECT tbl_employee.employee_id, expense_months.expense_month, tbl_expense_type.exp_type_id, tbl_expense_type.exp_type_text, SUM(expense_cost) AS monthly_exployee_expense
FROM tbl_employee
CROSS JOIN tbl_expense_type
CROSS JOIN
(
SELECT DISTINCT DATE_FORMAT(expense_date, '%Y%m') AS expense_month
FROM exp_tbl
) expense_months
LEFT OUTER JOIN exp_tbl
ON tbl_employee.employee_id = exp_tbl.employee_id
AND tbl_expense_type.exp_type_id = some_table.expense_type
AND expense_months.expense_month = DATE_FORMAT(exp_tbl.expense_date, '%Y%m')
GROUP BY tbl_employee.employee_id, expense_months.expense_month, tbl_expense_type.exp_type_id, tbl_expense_type.exp_type_text
) Sub1
GROUP BY employee_id, expense_month
this the query i had.. how to get only expense claimed employee list.
Example out put is:
3 Ramesh Kumar M 201402 Phone Expense=0=16,Consumable Purchase=0=11,Auto=0...
3 Ramesh Kumar M 201403 Consumable Purchase=0=11,Auto=0=6,2 wheeler=0=1,Lo...
3 Ramesh Kumar M 201404 Logistics/Transportation=0=18,Labour=0=13,Fuel=0=8...
3 Ramesh Kumar M 201405 Bus Travel=0=3,Office Vehicle=0=20,Others=0=15,Sta...
4 testexplevel1 201402 Others=0=15,Stay=0=10,Train Travel=0=5,Office Main...
4 testexplevel1 201403 Office Maintenance=0=17,Billable Purchase=0=12,Cal...
4 testexplevel1 201404 Call Taxi=0=7,4 wheeler=0=2,Guest House=0=19,Trans...
In that list not want all employee list. Only show ramesh data. Because that employee only has claimed.
Makes sense. You cross join all employees against all months and all expense types into a big cartesian product. Then you left join the actual expenses, so nothing gets excluded if there are no expenses.
So the quick fix would be to inner join the expenses. Doing so only gives you the employee-months for which an expense exists.
But doing so also allows you to remove the cross joins altogether and change it all to inner joins:
select
emp.employee_id,
DATE_FORMAT(ex.expense_date, '%Y%m'),
GROUP_CONCAT(CONCAT_WS('=', et.exp_type_text, ex.monthly_exployee_expense))
from
tbl_employee emp
inner join exp_tbl ex on ex.employee_id = emp.employee_id
inner join tbl_expense_type et on et.exp_type_id = ex.expense_type
group by
emp.employee_id,
DATE_FORMAT(ex.expense_date, '%Y%m')
Now, isn't that query much cleaner? :)

How to DISTINCT one column in stored procedure

I wrote one stored procedure.
My requirement is i have to show the data like if any No column has different Account_Names i have to show like Account_Name :Multipul(varchar))
Create PROCEDURE [dbo].[OpenVendorBIllsSP] (#FromDate Date,#ToDate Date)
AS
BEGIN
select
ROW_NUMBER() OVER(Order by vendor.VendorName ) AS ID,
PH.PurchasingHeaderID as No,
PH.TotalPriceCompanyCurrency as Balance,
acc.AccountName as [Account_Name],
PD.LineMemo as Memo,
from PurchasingHeader PH
LEFT OUTER JOIN TransactionType Trans ON PH.TransactionTypeID =Trans.TransactionTypeID
LEFT OUTER JOIN Vendor vendor on PH.VendorID=vendor.VendorID
LEFT OUTER JOIN PaymentTerm PT on PT.PaymentTermID = vendor.PaymentTermID
LEFT OUTER JOIN PurchasingDetail PD on PD.PurchasingHeaderID = PH.PurchasingHeaderID
LEFT OUTER JOIN Account Acc on Acc.AccountID= PD.FinancialAccountID
where PH.TransactionTypeID=7
Group by vendor.VendorName,
PH.PurchasingHeaderID,PH.TotalPriceCompanyCurrency,acc.AccountName
END
GO
with this result:
ID No Account_Name Balance Memo**
-------------------------------------------------------------
101 VB1000 Cash-Petty Cash 4000.00 Memo
102 VB1001 Accounts Receivable 5000.00 Memo
103 VB1003 Cash-PettyCash 6000.00 Memo
104 VB1003 Cash-PettyCash 6000.00 Memo
105 VB1004 UndepositedFunds 7000.00 Memo
I need this result :
ID No Account_Name Balance Memo
------------------------------------------------------
101 VB1000 Cash-PettyCash 4000.00 Memo1
102 VB1001 AccountsReceivable 5000.00 Memo2
103 VB1003 ---Multiple---- 6000.00 Memo3
104 VB1004 UndepositedFunds 7000.00 Memo4
Can any one tell me how can i write the sp to get aboue result.
Edited SP :
select
ROW_NUMBER() OVER(Order by vendor.VendorName ) AS ZID,
PH.PurchasingHeaderID as No,
PH.TotalPriceCompanyCurrency as Balance,
Case When count(PH.PurchasingHeaderID) > 1 Then 'Multipul' else acc.AccountName END
from PurchasingHeader PH
LEFT OUTER JOIN TransactionType Trans ON PH.TransactionTypeID =Trans.TransactionTypeID
LEFT OUTER JOIN Vendor vendor on PH.VendorID=vendor.VendorID
LEFT OUTER JOIN PaymentTerm PT on PT.PaymentTermID = vendor.PaymentTermID
LEFT OUTER JOIN PurchasingDetail PD on PD.PurchasingHeaderID = PH.PurchasingHeaderID
LEFT OUTER JOIN Account Acc on Acc.AccountID= PD.FinancialAccountID
where PH.TransactionTypeID=7
Group by vendor.VendorName,PH.PurchasingHeaderID ,
PH.PurchasingHeaderID,PH.TotalPriceCompanyCurrency,acc.AccountName
You could do a subsection that has everything, then GROUP BY acc.AccountName, PH.TotalPriceCompanyCurrency, etc and do a CASE WHERE COUNT(acc.AccountName) > 1