Get the count of records from another table - sql

I have a view that looks like this:
which is defined using this SQL statement:
SELECT
p.p_ccode AS C_CODE,
p.p_pcode AS P_CODE,
p.p_phcode AS PH_CODE,
PO.m_doc_type AS TYPE,
PO.crtime AS DATE
FROM
TABLE1 AS p
LEFT OUTER JOIN
DOCTABLE AS PO ON PO.m_ccode = p.p_ccode
AND PO.m_pcode = p.p_pcode
AND PO.m_phcode = p.p_phcode
Now I want to count the records for another table (TABLE 2) based on the C_CODE, P_CODE and PH_CODE and display it as a column TOTAL in my view.
How can I do this?

one way is to use subquery:
SELECT
p.p_ccode AS C_CODE,
p.p_pcode AS P_CODE,
p.p_phcode AS PH_CODE,
PO.m_doc_type AS TYPE,
PO.crtime AS DATE,
(select count(*) from tale2 t2 where t2.C_CODE = p.p_ccode and t2.P_CODE = p.P_CODE and t2.PH_CODE = p.PH_CODE) as total
FROM TABLE1 AS p
LEFT OUTER JOIN DOCTABLE AS PO
ON PO.m_ccode = p.p_ccode
AND PO.m_pcode = p.p_pcode
AND PO.m_phcode = p.p_phcode

Left join to it, group by and then count --
SELECT
p.p_ccode AS C_CODE,
p.p_pcode AS P_CODE,
p.p_phcode AS PH_CODE,
PO.m_doc_type AS TYPE,
PO.crtime AS DATE,
COUNT(P2.*) AS TOTAL
FROM TABLE1 AS p
LEFT OUTER JOIN DOCTABLE AS PO
ON PO.m_ccode = p.p_ccode
AND PO.m_pcode = p.p_pcode
AND PO.m_phcode = p.p_phcode
LEFT OUTER JOIN TABLE2 AS p2
ON p.m_ccode = p2.p_ccode
AND p.m_pcode = p2.p_pcode
AND p.m_phcode = p2.p_phcode
GROUP BY p.p_ccode, p.p_pcode, p.p_phcode, PO.m_doc_type, PO.crtime

use an CTE (Common Table Expression)
WITH CTE_COUNT
AS(
SELECT
[C_CODE]
,[P_CODE]
,[PH_CODE]
,COUNT(*) AS [TOTAL]
FROM [dbo].[TABLE2]
GROUP BY
[C_CODE]
,[P_CODE]
,[PH_CODE]
)
SELECT
t1.[C_CODE]
,t1.[P_CODE]
,t1.[PH_CODE]
,t1.[TYPE]
,t1.[DATE]
,t2.[TOTAL]
FROM [dbo].[TABLE1] AS t1
LEFT JOIN CTE_COUNT AS t2
ON t2.[C_CODE] = t1.[C_CODE]
AND t2.[P_CODE] = t1.[P_CODE]
AND t2.[PH_CODE] = t1.[PH_CODE]

Related

Group BY Expression column

we're trying to make our table add together all values in column 2 (QtyComp - an expression column of qtyorder * totalqty basically), where they have the same ItemNo (column 1).
So, we currently get the below:
ItemNo QtyCom
7441 3
7441 1
7441 5
What we want is it to return this:
ItemNo QtyCom
7441 9
Our code is below; I've bolded the part that we need it to sum the results of:
SELECT TOP (100) PERCENT ItemSpecs_2.itemno,
workorderdetails.qtycomplete *
ItemSpecFullStruc_2.totalqtyperroot AS QtyComp
FROM dbo.workorderdetails AS WorkOrderDetails
INNER JOIN dbo.itemspecfullstruc AS ItemSpecFullStruc_2
ON ItemSpecFullStruc_2.rootitemspecid =
workorderdetails.itemspecid
INNER JOIN dbo.itemspecs AS ItemSpecs_2
ON ItemSpecs_2.itemspecid = ItemSpecFullStruc_2.childitemspecid
INNER JOIN dbo.workorder AS WorkOrder_1
ON WorkOrder_1.workorderid = workorderdetails.workorderid
LEFT OUTER JOIN dbo.tobescheduled_completed
ON WorkOrder_1.workorderid =
dbo.tobescheduled_completed.workorderid
WHERE ( workorderdetails.completed = 1 )
AND ( workorderdetails.compdate > Getdate() - 42 )
GROUP BY ItemSpecs_2.itemno,
workorderdetails.qtyordered,
ItemSpecFullStruc_2.totalqtyperroot,
workorderdetails.[lineno],
workorderdetails.qtycomplete,
workorderdetails.compdate,
workorderdetails.qtycomplete * ItemSpecFullStruc_2.totalqtyperroot
We would really appreciate some ideas!
Thanks,
Trish
Try this
SELECT TOP (100) PERCENT ItemSpecs_2.itemno,
sum(workorderdetails.qtycomplete *
ItemSpecFullStruc_2.totalqtyperroot) AS QtyComp
FROM dbo.workorderdetails AS WorkOrderDetails
INNER JOIN dbo.itemspecfullstruc AS ItemSpecFullStruc_2
ON ItemSpecFullStruc_2.rootitemspecid =
workorderdetails.itemspecid
INNER JOIN dbo.itemspecs AS ItemSpecs_2
ON ItemSpecs_2.itemspecid = ItemSpecFullStruc_2.childitemspecid
INNER JOIN dbo.workorder AS WorkOrder_1
ON WorkOrder_1.workorderid = workorderdetails.workorderid
LEFT OUTER JOIN dbo.tobescheduled_completed
ON WorkOrder_1.workorderid =
dbo.tobescheduled_completed.workorderid
WHERE ( workorderdetails.completed = 1 )
AND ( workorderdetails.compdate > Getdate() - 42 )
GROUP BY ItemSpecs_2.itemno,
workorderdetails.qtyordered,
ItemSpecFullStruc_2.totalqtyperroot,
workorderdetails.[lineno],
workorderdetails.qtycomplete,
workorderdetails.compdate
Once you will use top for select statement, you need to use order by. you can try the following query.
SELECT TOP(100) PERCENT A.itemno,SUM(QtyComp) FROM
(SELECT ItemSpecs_2.itemno,
(workorderdetails.qtycomplete *
ItemSpecFullStruc_2.totalqtyperroot) AS QtyComp
FROM dbo.workorderdetails AS WorkOrderDetails
INNER JOIN dbo.itemspecfullstruc AS ItemSpecFullStruc_2
ON ItemSpecFullStruc_2.rootitemspecid =
workorderdetails.itemspecid
INNER JOIN dbo.itemspecs AS ItemSpecs_2
ON ItemSpecs_2.itemspecid = ItemSpecFullStruc_2.childitemspecid
INNER JOIN dbo.workorder AS WorkOrder_1
ON WorkOrder_1.workorderid = workorderdetails.workorderid
LEFT OUTER JOIN dbo.tobescheduled_completed
ON WorkOrder_1.workorderid =
dbo.tobescheduled_completed.workorderid
WHERE ( workorderdetails.completed = 1 )
AND ( workorderdetails.compdate > Getdate() - 42 ) ) A
GROUP BY A.itemno
ORDER BY A.itemno
Thanks
SELECT SUM(QTYCOM) OVER (PARTITION BY ITEMNO)
FROM
...

Table A drops rows in table B in SQL JOIN

I have two tables which I need joined. I have two select statements with the same columns except OrderValue and SalesTarget:
SELECT
b.TrnYear, b.TrnMonth, b.Branch, b.Salesperson, b.OrderValue
FROM
dbo.vw_jab_Consolidated_Orders as b
INNER JOIN
dbo.vw_jab_SalTargets as a ON a.Sequence2 = b.Salesperson
WHERE
b.TrnYear = '2017'
ORDER BY
a.TrnMonth
SELECT
a.TrnYear, a.TrnMonth, a.Sequence1, a.Sequence2, a.SalesTarget
FROM
dbo.vw_jab_SalTargets as a
WHERE
a.TrnYear = '2017' AND a.SequenceType = 'BR'
GROUP BY
a.TrnYear, a.TrnMonth, a.Sequence1, a.Sequence2, a.SalesTarget
My problem is that as there are months where there are no OrderValues, the SalesTarget value is being filtered out when I join the two tables as follows:
SELECT
a.TrnYear, SUM(a.SalesTarget) as SalesTarget, SUM(b.InvoicedSales) AS InvoicedSales
FROM
(SELECT
TrnYear, SUM(SalesTarget) AS SalesTarget
FROM
dbo.vw_jab_SalTargets
WHERE
(SequenceType = 'BR')
GROUP BY
SequenceType, TrnYear) AS A
LEFT JOIN
(SELECT
TrnYear, SUM(ActualSales) AS InvoicedSales
FROM
dbo.vw_jab_Consolidated_Sales
GROUP BY
TrnYear) AS b ON a.TrnYear = b.TrnYear
WHERE
a.TrnYear = '2017'
GROUP BY
a.TrnYear
You want a right outer join, instead of an inner join. For a right outer join, all columns of the right table are kept even if there is not a matching value in the left table.
Try this:
SELECT a.TrnYear, a.TrnMonth, SUM(a.SalesTarget) as SalesTarget, SUM(b.InvoicedSales) AS InvoicedSales
FROM (SELECT TrnYear, TrnMonth, SUM(SalesTarget) AS SalesTarget
FROM dbo.vw_jab_SalTargets
WHERE (SequenceType = 'BR')
GROUP BY SequenceType, TrnYear, TrnMonth) AS a RIGHT OUTER JOIN
(SELECT TrnYear, TrnMonth, SUM(ActualSales) AS InvoicedSales
FROM dbo.vw_jab_Consolidated_Sales
GROUP BY TrnYear, TrnMonth) AS b ON a.TrnYear = b.TrnYear and a.TrnMonth=b.TrnMonth
WHERE a.TrnYear = '2017'
GROUP BY a.TrnYear, a.TrnMonth
ORDER BY TrnMonth
You could switch to a RIGHT JOIN, but then if you have no InvoicedSales, you won't get any SalesTargets. I'd use a FULL OUTER JOIN like so:
SELECT COALESCE(a.TrnYear,b.TrnYear) AS TrnYear
,SUM(a.SalesTarget) AS SalesTarget
,SUM(b.InvoicedSales) AS InvoicedSales
FROM (
SELECT TrnYear
,SUM(SalesTarget) AS SalesTarget
FROM dbo.vw_jab_SalTargets
WHERE (SequenceType = 'BR')
GROUP BY SequenceType
,TrnYear
) AS a
FULL OUTER JOIN (
SELECT TrnYear
,SUM(ActualSales) AS InvoicedSales
FROM dbo.vw_jab_Consolidated_Sales
GROUP BY TrnYear
) AS b
ON a.TrnYear = b.TrnYear
WHERE a.TrnYear = '2017'
OR b.TrnYear = '2017'
GROUP BY COALESCE(a.TrnYear,b.TrnYear)
The COALESCE() is necessary so that the column will always return the TrnYear.

How to use GROUP BY for a column with an alias?

I have 3 tables
tblVendor, tblVendorItem and tblEventItem.
tblEventItem has the columns Quantity and Price.
I want to show a Vendor's VendorItem on a chart based on their Sales., where Sales will be a calculated as column (Quantity * Price).
I have tried the following query but it´s not working correctly. It says: Invalid column name: Sales.
SELECT tblEventItem.Quantity * tblEventItem.Price AS 'Sales', tblEventItem.VendorItemID, tblVendorItem.Name AS 'VendorItemName'
FROM tblEventService INNER JOIN
tblEventItem ON tblEventService.EventServiceID = tblEventItem.EventServiceID INNER JOIN
tblVendorItem ON tblVendorItem.VendorItemID = tblEventItem.VendorItemID INNER JOIN
tblVendor ON tblVendorItem.VendorID = tblVendor.VendorID
WHERE (tblEventService.ServiceID = 3)
GROUP BY 'Sales'
Use CROSS APPLY or OUTER APPLY for that. This does not affect performance, however it makes code more readable and easier to use.
-- MS SQL
CREATE TABLE #test
(
b INT,
c INT
);
INSERT INTO #test VALUES (1,2), (2,3), (3,4), (4,3)
SELECT s.Sales, COUNT(*) FROM #test a CROSS APPLY (SELECT b*c AS 'Sales') s
GROUP BY s.Sales;
In your case it will be something like:
SELECT
s.Sales ,
tblEventItem.VendorItemID ,
tblVendorItem.Name AS 'VendorItemName'
FROM
tblEventService
INNER JOIN tblEventItem ON tblEventService.EventServiceID = tblEventItem.EventServiceID
INNER JOIN tblVendorItem ON tblVendorItem.VendorItemID = tblEventItem.VendorItemID
INNER JOIN tblVendor ON tblVendorItem.VendorID = tblVendor.VendorID
CROSS APPLY (SELECT tblEventItem.Quantity * tblEventItem.Price Sales) s
WHERE
( tblEventService.ServiceID = 3 )
ORDER BY
'Sales' DESC;
It is very unclear what is need to be grouped by, but hope that with this query you can do your plans.
SELECT tblVendorItem.Name, tblEventItem.Quantity * tblEventItem.Price AS 'Sale'
FROM tblEventService INNER JOIN
tblEventItem ON tblEventService.EventServiceID = tblEventItem.EventServiceID INNER JOIN
tblVendorItem ON tblEventItem.VendorItemID = tblVendorItem.VendorItemID INNER JOIN
tblVendor ON tblVendorItem.VendorID = tblVendor.VendorID
WHERE (tblEventService.VendorID =#VendorID)
GROUP BY tblVendorItem.Name,tblEventItem.Quantity, tblEventItem.Price

JOIN / LEFT JOIN conflict in SQL Server

I have a tricky query. I need to select all recent versions of 2 types of members of administrator groups. Here is the query:
SELECT refGroup.*
FROM tblSystemAdministratorGroups refGroup
JOIN tblGroup refMem ON refGroup.AttributeValue = refMem.ObjectUID
This query will return all the administrator groups. The next step will be getting the members of these groups. Since I have 2 types of memberships (Explicit, Computed), I will have to use a LEFT JOIN to make sure that I am not excluding any rows.
SELECT refGroup.*
FROM tblSystemAdministratorGroups refGroup
-- The JOIN bellow can be excluded but it is here just to clarify the architecture
JOIN tblGroup refMem ON refGroup.AttributeValue = refMem.ObjectUID
LEFT JOIN tblGroup_ComputedMember cm ON refMem.ObjectUID = cm.GroupObjectID
LEFT JOIN tblGroup_ExplicitMember em ON refMem.ObjectUID = em.GroupObjectID
The last piece in the puzzle is to get the latest version of each member. For that I will have to use JOIN to exclude older versions:
JOIN (
SELECT MAX([ID]) MaxId
FROM [OmadaReporting].[dbo].tblGroup_ComputedMember
GROUP BY ObjectID
) MostRecentCM ON MostRecentCM.MaxId = cm.Id
and
JOIN (
SELECT MAX([ID]) MaxId
FROM [OmadaReporting].[dbo].tblGroup_ExplicitMember
GROUP BY ObjectID
) MostRecentEM ON MostRecentEM.MaxId = em.Id
The full query will be:
SELECT refGroup.*
FROM tblSystemAdministratorGroups refGroup
JOIN tblGroup refMem ON refGroup.AttributeValue = refMem.ObjectUID
LEFT JOIN tblGroup_ComputedMember cm ON refMem.ObjectUID = cm.GroupObjectID
JOIN (
SELECT MAX([ID]) MaxId
FROM [OmadaReporting].[dbo].tblGroup_ComputedMember
GROUP BY ObjectID
) MostRecentCM ON MostRecentCM.MaxId = cm.Id
LEFT JOIN tblGroup_ExplicitMember em ON refMem.ObjectUID = em.GroupObjectID
JOIN (
SELECT MAX([ID]) MaxId
FROM [OmadaReporting].[dbo].tblGroup_ExplicitMember
GROUP BY ObjectID
) MostRecentEM ON MostRecentEM.MaxId = em.Id
The issue is clear: The 2 JOIN to exclude old versions are also applied to the select statement and clearly no rows are returned. What would be the best solution to escape such situation and to return the intended values?
SELECT refGroup.*
FROM tblSystemAdministratorGroups refGroup
JOIN tblGroup refMem ON refGroup.AttributeValue = refMem.ObjectUID
LEFT JOIN (
select GroupObjectID, ID, max(ID) over (partition by ObjectID) as maxID
from tblGroup_ComputedMember
) cm ON refMem.ObjectUID = cm.GroupObjectID and cm.ID = cm.maxID
LEFT JOIN (
select GroupObjectID, ID, max(ID) over (partition by ObjectID) as maxID
from tblGroup_ExplicitMember
) em ON refMem.ObjectUID = em.GroupObjectID and em.ID = em.maxID
where cm.ID = cm.MaxID
What about using LEFT join in your last two joins?
LEFT JOIN (
SELECT MAX([ID]) MaxId
FROM [OmadaReporting].[dbo].tblGroup_ComputedMember
GROUP BY ObjectID
) MostRecentCM ON MostRecentCM.MaxId = cm.Id
And then in Where clause filter values as:
WHERE MostRecentCM.MaxId IS NOT NULL
OR
MostRecentEM.MaxId IS NOT NULL

Sum record data into one

I have this query which returns qty in each of my branch. now the branch has two WH_subType as you see in the attached diagram i have attached. I want to sum the 2 subtype and show its available qty. how can i do it.
my select query is like this
SELECT
dbo.WarehouseType.name AS Section,
dbo.WarehouseSubType.name AS WH_Type,
dbo.WarehouseSubType1.name AS WH_SubType,
dbo.Branch.name AS Branch,
(dbo.WarehouseProductQuantity.actualQuantity - dbo.WarehouseProductQuantity.reservedQuantity) AS AvailQty,
dbo.WarehouseProductQuantity.tafsilId AS Tafsil,
dbo.Tafsil.description AS Product_Name
FROM
dbo.WarehouseSubType
INNER JOIN
dbo.WarehouseType
ON
(
dbo.WarehouseSubType.warehouseTypeId = dbo.WarehouseType.id)
INNER JOIN
dbo.WarehouseSubType1
ON
(
dbo.WarehouseSubType.id = dbo.WarehouseSubType1.warehouseSubTypeId)
INNER JOIN
dbo.Warehouse
ON
(
dbo.WarehouseSubType1.id = dbo.Warehouse.warehouseSubType1Id)
INNER JOIN
dbo.Branch
ON
(
dbo.Warehouse.branchId = dbo.Branch.id)
INNER JOIN
dbo.WarehouseProductQuantity
ON
(
dbo.Warehouse.id = dbo.WarehouseProductQuantity.warehouseId)
INNER JOIN
dbo.TafsilLink
ON
(
dbo.WarehouseProductQuantity.tafsilId = dbo.TafsilLink.sourceId)
INNER JOIN
dbo.Tafsil
ON
(
dbo.TafsilLink.targetId = dbo.Tafsil.id)
INNER JOIN
dbo.FinishProduct
ON
(
dbo.Tafsil.id = dbo.FinishProduct.tafsilId)
INNER JOIN
dbo.Supplier
ON
(
dbo.FinishProduct.supplierId = dbo.Supplier.tafsilId)
WHERE
WarehouseSubType1.warehouseSubTypeId IN (1,4)
group by dbo.WarehouseProductQuantity.tafsilId
Have you tried a group by
SELECT SubType, SUM(qty) AS QtySum
GROUP BY SubType
Every grouped by column should be in your select. Note: for every column you group by it further sub divides the data
Update based on OP comment:
If you want other columns you need to do something like
SELECT s.WH_SubType,s.AvailQty, t.other_cols
from
(SELECT
dbo.WarehouseSubType1.name AS WH_SubType,
sum(dbo.WarehouseProductQuantity.actualQuantity - dbo.WarehouseProductQuantity.reservedQuantity) AS AvailQty
FROM
table
GROUP BY
dbo.WarehouseSubType1.name) s
left join table t on t.dbo.WarehouseSubType1.name = s.WH_SubType;
For reference see this question: How do I use "group by" with three columns of data?
UPDATE 2:
SELECT
dbo.WarehouseType.name AS Section,
dbo.WarehouseSubType.name AS WH_Type,
dbo.WarehouseSubType1.name AS WH_SubType,
dbo.Branch.name AS Branch,
SumTable.AvailQty,
SumTable.Tafsil,
dbo.Tafsil.description AS Product_Name
FROM
dbo.WarehouseSubType
INNER JOIN
dbo.WarehouseType
ON
(
dbo.WarehouseSubType.warehouseTypeId = dbo.WarehouseType.id)
INNER JOIN
dbo.WarehouseSubType1
ON
(
dbo.WarehouseSubType.id = dbo.WarehouseSubType1.warehouseSubTypeId)
INNER JOIN
dbo.Warehouse
ON
(
dbo.WarehouseSubType1.id = dbo.Warehouse.warehouseSubType1Id)
INNER JOIN
dbo.Branch
ON
(
dbo.Warehouse.branchId = dbo.Branch.id)
INNER JOIN
dbo.WarehouseProductQuantity
ON
(
dbo.Warehouse.id = dbo.WarehouseProductQuantity.warehouseId)
INNER JOIN
dbo.TafsilLink
ON
(
dbo.WarehouseProductQuantity.tafsilId = dbo.TafsilLink.sourceId)
INNER JOIN
dbo.Tafsil
ON
(
dbo.TafsilLink.targetId = dbo.Tafsil.id)
INNER JOIN
dbo.FinishProduct
ON
(
dbo.Tafsil.id = dbo.FinishProduct.tafsilId)
LEFT JOIN (SELECT
sum(dbo.WarehouseProductQuantity.actualQuantity - dbo.WarehouseProductQuantity.reservedQuantity) AS AvailQty,
dbo.WarehouseProductQuantity.tafsilId AS Tafsil
FROM
dbo.WarehouseProductQuantity
group by dbo.WarehouseProductQuantity.tafsilId) SumTable on dbo.Tafsil.id = SumTable.Tafsil
WHERE
WarehouseSubType1.warehouseSubTypeId IN (1,4)
You need to do something like
SELECT SUM(AvailQty), ... FROM ... WHERE ... GROUP BY WH_SubType
http://www.w3schools.com/sql/sql_func_sum.asp
http://www.w3schools.com/sql/sql_groupby.asp