Error on Group by method - sql-server

I wrote a query to combine records in multiple tables. Tables named by Purchase Order, Purchase Order Item
[ Note: The column names are not original names, it just for a model data]
In purchase order table have the order details like this,
id date vendorid totalitems totalqty grossamnt netamnt taxamt
----------------------------------------------------------------------------
1 03/10/17 00001 2 6 12000 13000 1000
Purchase Order Item table have the order details like this,
poid id productcode qty rate tax(%) taxamnt total
--------------------------------------------------------
1 1 12001 3 6000 2.5 500 6500
2 1 12000 3 6000 2.5 500 6500
My Query is,
select po.POID,po.SupplierId,po.TotalItems from
PurchaseOrder po, PurchaseOrderItem poi where po.POID=poi.POID group by
po.POID, po.SupplierId,po.TotalItems
Query returns,
id vendorid totalitems
--------------------------
1 00001 2
1 00001 2
Expected Output is,
id vendorid totalitems
------------------------
1 00001 2

You are using an outdated join method, have a read here:
ANSI vs. non-ANSI SQL JOIN syntax
You are also joining to another table, but never use it:
select po.POID,po.SupplierId,po.TotalItems
from PurchaseOrder po, PurchaseOrderItem poi
where po.POID=poi.POID
group by po.POID, po.SupplierId,po.TotalItems
Can just be:
select po.POID,po.SupplierId,po.TotalItems
from PurchaseOrder po
group by po.POID, po.SupplierId,po.TotalItem
OR
select DISTINCT
po.POID,
po.SupplierId,
po.TotalItems
from PurchaseOrder po

Related

Joined tables - how to aggregate problem (sum)?

I have two tables joined like this:
SELECT count(DISTINCT T1.ContractNumber) AS nr_of_contracts,
count(T3.DateofInstallmentPayment) AS nr_of_paid_installents,
count(T3.DateofDueInstallment) AS nr_of_installments,
sum(T1.DisbursementAmount) AS disbursed_amount
FROM q.T1
LEFT JOIN q.T3
ON T1.ContractNumber=T3.ContractNumber
WHERE DateOfDisbursement BETWEEN '2019-12-01' AND '2019-12-31'
AND T3.DateofDueInstallment < GETDATE()
where T1 table contains data about clients (per contract number) and T3 about their payment schedules (per every instalment).
What I want is to have paid off amount (disbursement amount) of contracts from table T1 (aggregated by contract number) and not by every instalment. When I tried to select just sum(T1.Disbursement amount) then I receive sum but for all instalment which is incorrect.
T1:
Contract Number
DisbursementDate
Disbursement Amount
1
2019-12-01
1000
2
2019-12-01
2000
3
2019-12-01
3000
T3:
Contract Number
DateofDueInstallment
DateofInstallmentPayment
1
2020-01-01
2020-01-01
1
2020-02-01
2020-02-06
1
2020-03-01
2020-04-01
What I get after joining two tables for Contract Number = 1 is sum(DisbursementAmount) = 3000.
Contract Number
sum(DisbursementAmount)
1
3000
What I want after joining two tables for Contract Number = 1 is sum(DisbursementAmount) = 1000.
Contract Number
sum(DisbursementAmount)
1
1000
Something like this,not tested - a subquery with a different aggregation column
SELECT T1.product, T1.NrOfInstallment, count(DISTINCT T1.ContractNumber),
SELECT paid_amound FROM(SELECT ContractNumber, sum(tt.DisbursementAmount + (tt.ContractNumber*0.01))
- sum(tt.ContractNumber*0.01) as paid_amount
FROM abc.T1 as tt WHERE tt.ContractNumber = T1.ContractNumber GROUP BY ContractNumber) AS t)
FROM abc.T1
LEFT JOIN bde.T3
ON T1.ContractNumber=T3.ContractNumber
GROUP BY T1.product, T1.NrOfInstallment

Sql Server - Get SUM() of values for only Active Users

I have a requirement where i need to get Total Active Employees and Total Sales by RegionId
My query result should be like below.
RegionId | TotalEmployees | TotalSales | Average
1 10 100 10
2 3 15 5
My front end application will pass all the RegionIds as a single string separated by a comma, my query parameter is of type VARCHAR() and the Input paramter will look like '1,2,3,4,7,14,26' and there can be upto 20 Region Ids in a single string separated by a comma.
SELECT E.[RegionId] as RegionId
,COUNT(E.[EmployeeId) AS TotalEmployees
,(SELECT SUM([Sale])
FROM dbo.[Sales]
WHERE RegionId = R.[RegionId]
) AS TotalSales
,TotalSales/TotalEmployees AS Average
FROM dbo.[Employee]
JOIN [dbo].[ufn_StringSplit](#RegionIdCollection, ',') RegionId
ON E.RegionId = CAST(RegionId.[Data] AS Varchar(5000))
WHERE E.[Active] = 1
GROUP BY E.[RegionId]
My Employee table structures look alike below
EmployeeId | Name | RegionId | Active
100 Tom 2 1
101 Jim 4 0
103 Ben 2 1
Sales Table
SaleId | EmployeeId| RegionId | Sale
1 100 2 3500
2 101 4 2000
3 100 2 1500
Now my issue is when i am getting TotalSales the below query gets all the sales by RegionId, but i need to get All the sales done by only current Active employees in the Employee table
(SELECT SUM([Sale])
FROM dbo.[Sales]
WHERE RegionId = R.[RegionId]
) AS TotalSales
There is no reason to use a sub-select to find the sum of sales here, that will result in running that query for each and every row. You want to aproach this in a set based way which means you need to join and group appropriately:
with s as
(
select e.RegionId
,e.EmployeeId
,sum(s.Sale) as EmployeeSales
from dbo.ufn_StringSplit(#RegionIdCollection, ',') as r
join dbo.Employee as e
on r.RegionId = CAST(r.[Data] AS varchar(20)) -- Do you really need 5000 characters here?
left join dbo.Sales as s
on r.RegionId = s.RegionId
and e.EmployeeId = s.EmployeeId
where e.Active = 1
group by e.RegionId
,e.EmployeeId
)
select s.RegionId
,count(s.EmployeeId) as TotalEmployees
,sum(s.EmployeeSales) as TotalSales
,sum(s.EmployeeSales)/count(s.EmployeeId) as Average
from s
group by s.RegionId

SQL Server query involving subqueries - performance issues

I have three tables:
Table 1: | dbo.pc_a21a22 |
batchNbr Other columns...
-------- ----------------
12345
12346
12347
Table 2: | dbo.outcome |
passageId record
---------- ---------
00003 200
00003 9
00004 7
Table 3: | dbo.passage |
passageId passageTime batchNbr
---------- ------------- ---------
00001 2015.01.01 12345
00002 2016.01.01 12345
00003 2017.01.01 12345
00004 2018.01.01 12346
What I want to do: for each batchNbr in Table 1 get first its latest passageTime and the corresponding passageID from Table 3. With that passageID, get the relevant rows in Table 2 and establish whether any of these rows contains the record 200. Per passageId there are at most 2 records in Table 2
What is the most efficient way to do this?
I have already created a query that works, but it's awfully slow and thus unfit for tables with millions of rows. Any suggestion on how to either change the query or do it another way? Altering the table structure is not an option, I only have read rights to the database.
My current solution (slow):
SELECT TOP 50000
a.batchNbr,
CAST ( CASE WHEN 200 in (SELECT TOP 2 record FROM dbo.outcome where passageId in (
SELECT SubqueryResults.passageId From (SELECT Top 1 passageId FROM dbo.passage pass WHERE pass.batchNbr = a.batchNbr ORDER BY passageTime Desc) SubqueryResults
)
) then 1 else 0 end as bit) as KGT_IO_END
FROM dbo.pc_a21a22 a
The desired output is:
batchNbr 200present
--------- ----------
12345 1
12346 0
I suggest you use table joining rather than subqueries.
select
a.*, b.*
from
dbo.table1 a
join
dbo.table2 b on a.id = b.id
where
/*your where clause for filtering*/
EDIT:
You could use this as a reference Join vs. sub-query
Try this
SELECT TOP 50000 a.*, (CASE WHEN b.record = 200 THEN 1 ELSE 0 END) AS
KGT_IO_END
FROM dbo.Test1 AS a
LEFT OUTER JOIN
(SELECT record, p.batchNbr
FROM dbo.Test2 AS o
LEFT OUTER JOIN (SELECT MAX(passageId) AS passageId, batchNbr FROM
dbo.Test3 GROUP BY batchNbr) AS p ON o.passageId = p.passageId
) AS b ON a.batchNbr = b.batchNbr;
The MAX subquery is to get the latest passageId by batchNbr.
However, your example won't get the record 200, since the passageId of the record with 200 is 00001, while the latest passageId of the batchNbr 12345 is 00003.
I used LEFT OUTER JOIN since the passageId from Table2 no longer match any of the latest passageId from Table3. The resulting subquery would have no records to join to Table1. Therefore INNER JOIN would not show any records from your example data.
Output from your example data:
batchNbr KGT_IO_END
12345 0
12346 0
12347 0
Output if we change the passageId of record 200 to 00003 (the latest for 12345)
batchNbr KGT_IO_END
12345 1
12346 0
12347 0

sql server 2012 merge values from two tables

I have two tables
tblA(sn, ID int pk, name varchar(50), amountA decimal(18,2))
and
tblB(ID int fk, amountB decimal(18,2))
here: tblA occures only once and tblB may occure multiple time
I need the query to display data like:
sn ID name AmountA amountB Balance
1 1001 abc 5000.00 5000.00
2 1002 xyz 10000.00
1002 4000.00 6000.00 (AmountA-AmountB)
3 1003 pqr 15000.00
1003 4000.00
1003 3000.00
1003 2000.00 6000.00 (AmountA-sum(AmountB))
Please ask if any confusion
I tried using lag and lead function but I couldnot get the desire result, Please help.
Since you are using SQL Server 2012, you can use a partition with an aggregate function (SUM):
SELECT t.sn,
t.ID,
t.name,
t.credits AS AmountA,
t.debits AS amountB,
SUM(t.credits - t.debits) OVER (PARTITION BY t.ID ORDER BY t.debits, t.credits) AS Balance
FROM
(
SELECT sn,
ID,
name,
AmountA AS credits,
0 AS debits
FROM tblA
UNION ALL
SELECT 0 AS sn,
ID,
NULL AS name,
0 AS credits,
amountB AS debits
FROM tblB
) t
ORDER BY t.ID,
t.debits,
t.credits
Explanation:
Since the records in tables A and B each represent a single transaction (i.e. a credit or debit), using a UNION query to bring both sets of data into a single table works well here. After this, I compute a rolling sum using the difference between credit and debit, for each record, for each ID partition group. The ordering is chosen such that credits appear at the top of each partition while debits appear on the bottom.

Filter two table rows by using group by with join in SQL Server

I have two tables as Sales and SalesDocument.
Sales Table
RequestId(PrimaryKey) ReqType DateTime
--------- ------- --------
1 Buy 22/10/2015
2 Buy 03/11/2015
3 Sell 10/11/2015
4 Return 11/12/2015
6 Sell 11/12/2015
7 Buy 20/12/2015
Sales Document Table
RequestId(Ref.Key(FK)) ReqDocument ReqDocURL
--------- ----------- ---------
2 Doc1 Http://..Doc1.PDF
3 Doc2 Http://..Doc2.PDF
3 Doc3 Http://..Doc3.PDF
4 Doc1 Http://..Doc1.PDF
4 Doc2 Http://..Doc2.PDF
4 Doc3 Http://..Doc3.PDF
6 Doc2 Http://..Doc2.PDF
6 Doc3 Http://..Doc3.PDF
Now I need to select the records in both tables by using RequestId(as Ref.Key) and the condition are,
1)In 1st Table,Need to get distinct ReqType(FirstColumn:RequestType) and It's count(SecondColumn:RequestTypeCount) based between two date ranges.
2)In 2nd Table, Need to calculate total no.of requested documents(ThirdColumn:SumOfReqDocument) by using RequestType(RequestType is not in 2nd table, hence we need to map with 1st table(sales) by RequestId and get the sum of documents.
The output should be,
RequestType RequestTypeCount SumOfReqDocument
----------- ---------------- ----------------
Buy 3 1
Sell 2 4
Return 1 3
I tried some SQL query but it does not result the actual result. Please help me on this SQL query\Suggest me some other query.
My Query is,
SELECT ReqType as RequestType,count(ReqType) as RequestTypeCount,count(salesDoc.DocumentURL) as SumOfReqDocument FROM Sales sales inner join SalesDocument salesDoc on
sales.RequestId=salesDoc.RequestId where sales.EndDate >= '2015-10-22 10:34:09.000' AND sales.EndDate <= '2015-12-31 00:00:00.000'
group by sales.ReqType
You may try change the INNER JOIN to LEFT JOIN, and COUNT DISTINCT ReqestID for RequestTypeCount
SELECT ReqType as RequestType
,count(DISTINCT sales.RequestId) as RequestTypeCount
,count(salesDoc.ReqDocURL) as SumOfReqDocument
FROM Sales sales
LEFT JOIN SalesDocument salesDoc
ON sales.RequestId=salesDoc.RequestId
WHERE sales.EndDate >= '2015-10-21 10:34:09.000' AND sales.EndDate <= '2015-12-31 00:00:00.000'
group by sales.ReqType

Resources