How to use PIVOT in SQL for this sample - sql

How do I pivot a results query?
Currently it looks like this
| Date | Count | BankName |
+---------+----------+----------+
| 970401 | 87 | Saderat |
| 970401 | 25 | Melli |
| 970401 | 11 | Sina |
into this
|Date | Saderat | Melli | Sina |
+---------+----------+----------+----------+
|970401 | 87 | 25 | 11 |
I tried the following but it's not working
SELECT
PayDate AS [Date],
COUNT(*) AS [Count], b.BankName
FROM
Payments p
INNER JOIN
dbo.Accounts a ON a.AccountId = p.CashAccountId
INNER JOIN
dbo.Banks b ON b.BankId = a.BankId
WHERE
PayTypeId = 21.101
AND PayDate BETWEEN '970401' AND '970412'
GROUP BY
PayDate, b.BankName
ORDER BY
paydate
or
SELECT
x.PayDate AS 'Date',
b.BankName
FROM
(SELECT
p.PayDate, p.PaymentId, p.CashAccountId
FROM
Payments p
WHERE
PayTypeId = 21.101
AND PayDate BETWEEN '970401' AND '970412') AS x
INNER JOIN
dbo.Accounts a ON a.AccountId = x.CashAccountId
INNER JOIN
dbo.Banks b ON b.BankId = a.BankId
PIVOT
(COUNT(PaymentId) FOR PayDate IN (bankid)) AS Pivotable

You can try following SQL for required results:
SELECT PayDate, Saderat, Melli, Sina
FROM
(SELECT PayDate , COUNT(*) AS [Count] , b.BankName
FROM Payments p INNER JOIN dbo.Accounts a ON a.AccountId = p.CashAccountId
INNER JOIN dbo.Banks b ON b.BankId = a.BankId
WHERE PayTypeId = 21.101 AND PayDate BETWEEN '970401' AND '970412'
GROUP BY PayDate , b.BankName
ORDER BY paydate) AS SourceTable
PIVOT
(
SUM([Count])
FOR BankName IN (Saderat, Melli, Sina)
) AS PivotTable;

You can do aggregation :
SELECT PayDate AS [Date],
SUM(CASE WHEN b.BankName = 'Saderat' THEN 1 ELSE 0 END) AS Saderat,
. . .
FROM Payments p INNER JOIN
dbo.Accounts a
ON a.AccountId = p.CashAccountId INNER JOIN
dbo.Banks b
ON b.BankId = a.BankId
WHERE PayTypeId = 21.101 AND PayDate BETWEEN '970401' AND '970412'
GROUP BY PayDate
ORDER BY paydate;

You can use PIVOT function in SQL Server, try following query:
SELECT date, [Saderat],[Melli],[Sina]
FROM YourTableName
PIVOT( MAX(count)
FOR BankName IN ([Saderat],[Melli],[Sina])) AS p

You could PIVOT
SELECT *
FROM
(
SELECT
p.PayDate AS [Date],
b.BankName
FROM dbo.Payments p
JOIN dbo.Accounts a ON a.AccountId = p.CashAccountId
JOIN dbo.Banks b ON b.BankId = a.BankId
WHERE p.PayTypeId = 21.101
AND p.PayDate BETWEEN CAST('1997-04-01' AS DATE) AND CAST('1997-04-12' AS DATE)
) src
PIVOT
(
COUNT(*)
FOR BankName IN (...) -- put quoted list of bank names here
) pvt
ORDER BY [Date]

Related

FULL OUTER JOIN of two INNER JOINs

I have three tables.
My Table Order has an Id and a Date.
Likewise my table Delivery has an Id and a Date.
My third table Part has an Id, and two foreign keys to Order and Delivery: OrderId, DeliveryId.
I want to create a query that gives me an overview over the count of orders and deliveries per month, like this:
+------+-------+------------+---------------+
| Year | Month | OrderCount | DeliveryCount |
+------+-------+------------+---------------+
| 2021 | 2 | 10 | 12 |
+------+-------+------------+---------------+
| 2021 | 1 | 234 | 213 |
+------+-------+------------+---------------+
| ... | ... | ... | ... |
+------+-------+------------+---------------+
So I created a query that gives me the orders per month:
SELECT
MONTH(o.[Date]) AS [Month],
YEAR(o.[Date]) AS [YEAR],
COUNT(p.Id) AS OrderCount
FROM
Part AS p
INNER JOIN
[Order] AS o ON o.Id = p.OrderId
GROUP BY
MONTH(o.[Date]), YEAR(o.[Date])
and one for the deliveries per month:
SELECT
MONTH(d.[Date]) AS [Month],
YEAR(d.[Date]) AS [YEAR],
COUNT(p.Id) AS DeliveryCount
FROM
Part AS p
INNER JOIN
Delivery AS d ON d.Id = p.DeliveryId
GROUP BY
MONTH(d.[Date]), YEAR(d.[Date])
But now I am struggling with joining them. I think I need a FULL OUTER JOIN, because I need the Month/Year/DeliveryCount when there is no order but deliveries and vice versa.
What I have tried is
SELECT
MONTH(o.Date) AS [Month]
YEAR(o.Date) as [Year]
COUNT(p.Id) as OrderCount
FROM
Part AS p
INNER JOIN
[Order] AS o ON o.Id = p.OrderId
GROUP BY
MONTH(o.Date), Year(o.Date)
FULL OUTER JOIN
(SELECT
MONTH(d.Date) AS [Month]
YEAR(d.Date) as [Year]
COUNT(pp.Id) as DeliveryCount
FROM
Part AS pp
INNER JOIN
Delivery AS d ON d.Id = pp.DeliveryId
GROUP BY
MONTH(d.Date), YEAR(d.Date)) AS d ON d.[Month] = MONTH(o.Date) AND d.[Year] = YEAR(o.Date)
But that's not how FULL OUTER JOINS work.
How do I get a full outer of these two inner joins?
Or is this approach of outer joining two inner joins wrong in the first place?
You have to treat your two queries as sub-queries.
This should give you the desired result
Select Orders.OrderCount, Deliveries.DeliveryCount
from (
SELECT
MONTH(o.Date) AS [Month]
YEAR(o.Date) AS [YEAR]
COUNT(p.Id) AS OrderCount
FROM
Part AS p
INNER JOIN
[Order] AS o ON o.Id = p.OrderId
GROUP BY
MONTH(o.Date), YEAR(o.Date)
) Orders
FULL OUTER JOIN
(
SELECT
MONTH(d.Date) AS [Month]
YEAR(d.Date) AS [YEAR]
COUNT(p.Id) AS DeliveryCount
FROM
Part AS p
INNER JOIN
Delivery AS d ON d.Id = p.DeliveryId
GROUP BY
MONTH(d.Date), YEAR(d.Date) ) Deliveries
on Orders.Month = Deliveries.Month
and Orders.Year = Deliveries.Year
This would solve your problem.
In case you have months/year missing, use other join.
WITH OrdersMonth AS (
SELECT
MONTH(o.Date) AS [Month]
YEAR(o.Date) AS [YEAR]
COUNT(p.Id) AS OrderCount
FROM
Part AS p
INNER JOIN
[Order] AS o ON o.Id = p.OrderId
GROUP BY
MONTH(o.Date), YEAR(o.Date)
), DeliveriesMonth AS (
SELECT
MONTH(d.Date) AS [Month]
YEAR(d.Date) AS [YEAR]
COUNT(p.Id) AS DeliveryCount
FROM
Part AS p
INNER JOIN
Delivery AS d ON d.Id = p.DeliveryId
GROUP BY
MONTH(d.Date), YEAR(d.Date)
)
SELECT om.YEAR
,om.Month
,om.OrderCount
,dm.DeliveryCount
FROM OrdersMonth om
LEFT JOIN DeliveriesMonth dm ON om.om.YEAR = dm.YEAR AND om.Month = dm.Month

Selecting the MIN(date) and the MAX(date) with the MAX(date) Freight Values

I need the MIN(Orderdate) and MAX(Orderdate) with the MAX(Orderdate) Freight values.
I've tried using a CTE and I am struggling to eliminate duplicate rows for the CustomerID
USE Northwind
GO
WITH CTE AS (
SELECT a.customerID,
MAX(b.OrderDate) AS LastOrder,
MIN(b.OrderDate) AS FirstOrder
FROM Orders AS b
INNER JOIN Customers AS a
ON b.CustomerID = a.CustomerID
GROUP BY a.CustomerID
)
SELECT CTE.customerID, CTE.FirstOrder, d.OrderDate as LastOrder, d.Freight
FROM CTE
INNER JOIN Orders as d
On CTE.CustomerID = d.CustomerID
GROUP BY CTE.CustomerID, CTE.FirstOrder, d.Freight, d.OrderDate
HAVING d.OrderDate = MAX(d.OrderDate)
I am trying to get these results which should display 89 records.
CustomerID FirstOrder LastOrder Freight
| ALFKI | 1997-08-25 | 1998-04-09 | 1.21 |
| ANATR | 1996-09-18 | 1998-03-04 | 39.92 |
| ANTON | 1996-11-27 | 1998-01-28 | 58.43 |
| AROUT | 1996-11-15 | 1998-04-10 | 33.80 |
| BERGS | 1996-08-12 | 1998-03-04 | 151.52 |
Just to Keep it simple and in line with the question. The Subquery CTE already has the customerID and the LastOrder(Max Order Date). Joining the LastOrder column in CTE to the Order tables OrderDate will give the expected results.
and d.OrderDate = CTE.LastOrder
Full Query:
WITH CTE AS (
SELECT a.customerID,
MAX(b.OrderDate) AS LastOrder,
MIN(b.OrderDate) AS FirstOrder
FROM Orders AS b
INNER JOIN Customers AS a
ON b.CustomerID = a.CustomerID
GROUP BY a.CustomerID
)
SELECT CTE.customerID, CTE.FirstOrder, d.OrderDate as LastOrder, d.Freight
FROM CTE
INNER JOIN Orders as d
On CTE.CustomerID = d.CustomerID
and d.OrderDate = CTE.LastOrder
Just use conditional aggregation:
SELECT o.customerID,
MAX(o.OrderDate) AS LastOrder,
MIN(o.OrderDate) AS FirstOrder,
MAX(CASE WHEN seqnum = 1 THEN o.freight END) as lastFreight
FROM (SELECT o.*,
ROW_NUMBER() OVER (PARTITION BY o.customerID ORDER BY o.OrderDate DESC) as seqnum
FROM Orders o
) o
GROUP BY o.CustomerID;
Note that you do not appear to need the Customer table. All the information you need is in Orders (I doubt you are using Customer to remove rows.)

SQL Server - Get the Total Count with the TOP 1 product

I need to be able to find the total count of orders placed by a customer, but also find the top product in one query. For example in the following structure,
CREATE TABLE #Cust (CustId INT, CustName VARCHAR(50))
CREATE TABLE #Product (ProductId INT, ProductName VARCHAR(10) )
CREATE TABLE #Orders (CustId INT, ProductId INT, OrderTaken BIT)
INSERT #Cust
( CustId, CustName )
VALUES ( 1, 'Paul' ),
( 2, 'F' ),
( 3, 'Francis' )
INSERT #Product
( ProductId, ProductName )
VALUES ( 1, 'Table' ),
( 2, 'Chair' )
INSERT #Orders
( CustId, ProductId, OrderTaken )
VALUES ( 1, 1, 1 ),
( 1, 1, 1 ),
( 1, 2, 1 ),
( 2, 1, 1 )
I have come up with a query,
SELECT * FROM #Cust AS C OUTER APPLY
(
SELECT TOP 1 SQ.ProductId, SUM(SQ.TotalCount) AS TotalQty FROM
(
SELECT O.ProductId, COUNT(*) TotalCount
FROM #Orders AS O WHERE O.CustId = C.CustId
GROUP BY O.CustId , O.ProductId
) SQ
GROUP BY SQ.ProductId
) X
But, that is not giving me the result I am looking for, for Paul it is giving me the correct ProductId, but a count of that product alone.
I want the a Query to return,
CustId | CustName | ProductId | TotalQty
--------+---------------+---------------+------------
1 | Paul | 1 | 3
2 | F | 1 | 1
3 | Francis | NULL | NULL
One option is with the WITH TiES clause
Select Top 1 with ties
CustID
,CustName
,ProductId
,TotalQty
From (
Select C.CustID
,C.CustName
,O.ProductId
,TotalQty = count(O.CustId) over (Partition By O.CustID)
,ProdCount = count(O.CustId) over (Partition By O.CustID,O.ProductID)
From #Cust C
Left Join #Orders O on C.CustID=O.CustId
) A
Order by Row_Number() over (Partition By CustID Order by ProdCount Desc)
Returns
CustID CustName ProductId TotalQty
1 Paul 1 3
2 F 1 1
3 Francis NULL 0
Try
SELECT c.*, ProductId, CustProdTotal, CustTotal
FROM #Cust AS C
OUTER APPLY (
select top(1) with ties ProductId, CustProdTotal, CustTotal
from (
select *, count(OrderTaken) over() as CustTotal
, count(OrderTaken) over(partition by ProductId) as CustProdTotal
from #Orders o
where O.CustId = C.CustId) x
order by row_number() over(order by CustProdTotal desc)
) z
Similar question has been answered with a nice explanation here
(Benefit here : common concept of join used).
(disadvantage : query may not be efficient for large records)
I have modified the solution for your scenario
SELECT s.CustId, s.CustName, s.ProductId, m.TotalOrderTaken
FROM (SELECT p.CustId, p.CustName, t.ProductId, COUNT(*) AS ProductIdCount
FROM #Cust AS p
JOIN #Orders AS t
ON p.CustId = t.CustId
GROUP BY p.CustId, p.CustName, t.ProductId
) AS s
JOIN (SELECT s.CustId, MAX(s.ProductIdCount) AS MaxProductIdCount, sum(s.ProductIdCount) TotalOrderTaken
FROM (
SELECT p.CustId,p.CustName, t.ProductId, COUNT(*) AS ProductIdCount
FROM #Cust AS p
JOIN #Orders AS t
ON p.CustId = t.CustId
GROUP BY p.CustId, p.CustName, t.ProductId
) AS s
GROUP BY s.CustId
) AS m
ON s.CustId = m.CustId AND s.ProductIdCount = m.MaxProductIdCount
Works on SQL Server 2005 onwards.
;with cte1 as (select c.custid, c.custname, o.productid, count(*) as TotalQty
from #cust c
left join #orders o on c.custid=o.custid
left join #product p on p.productid=o.productid
group by c.custid, c.custname, o.productid)
,cte2 as (select custid, max(TotalQty) as TopQty
from cte1
group by custid)
Select cte1.*
from cte1
inner join cte2 on cte1.custid=cte2.custid and cte1.TotalQty=cte2.Topqty
If you can't use the over clause, this would work (obviously, a lot more work compared to an over clause):
SELECT custOrderAll.CustId
, custOrderAll.CustName
, MaxOrder.ProductId
, MAX(custOrderAll.cntAll) TotalQty
FROM (
SELECT c.CustId
, c.CustName
, COUNT(O.ProductId) cntAll
FROM #Cust AS C
LEFT JOIN #Orders AS O
ON O.CustId = C.CustId
GROUP BY c.CustId
, c.CustName
) custOrderAll
LEFT JOIN (
SELECT custOrderMAX.CustId
, custOrderMAX.CustName
, custOrderMAX.ProductId
FROM (
SELECT c.CustId
, c.CustName
, O.ProductId
, COUNT(O.ProductId) cntMax
FROM #Cust AS C
LEFT JOIN #Orders AS O
ON O.CustId = C.CustId
GROUP BY c.CustId
, c.CustName
, O.ProductId
) custOrderMAX
INNER JOIN (
SELECT mxCnt.CustId
, mxCnt.CustName
, MAX(mxCnt.cntMax) mxCnt
FROM (
SELECT c.CustId
, c.CustName
, O.ProductId
, COUNT(O.ProductId) cntMax
FROM #Cust AS C
LEFT JOIN #Orders AS O
ON O.CustId = C.CustId
GROUP BY c.CustId
, c.CustName
, O.ProductId
) mxCnt
GROUP BY mxCnt.CustId
, mxCnt.CustName
) custOrderMAXCnt
ON custOrderMAXCnt.CustId = custOrderMAX.CustId
AND custOrderMAXCnt.mxCnt = custOrderMAX.cntMax
) MaxOrder
ON MaxOrder.CustId = custOrderAll.CustId
AND MaxOrder.CustName = custOrderAll.CustName
GROUP BY custOrderAll.CustId
, custOrderAll.CustName
, MaxOrder.ProductId
Result:
+--------+----------+-----------+----------+
| CustId | CustName | ProductId | TotalQty |
+--------+----------+-----------+----------+
| 1 | Paul | 1 | 3 |
| 2 | F | 1 | 1 |
| 3 | Francis | NULL | 0 |
+--------+----------+-----------+----------+

Count Customers based on item master

I need you to help me on writing two queries in SQL Server 2008 that shows the following information based on item master:
Brand wise count on customer master plus customer who purchased the brand
Item Wise count of customer master plus customer who purchased the item
Here the link that shows the table information and the query which I tried.
Click here to view the table in SQL Fiddle
SELECT
brandname,
division,
route,
DivisionTotalCustomersCount = MAX(DivisionTotalCustomersCount),
RouteTotalCustomersCount = MAX(RouteTotalCustomersCount),
PurchasedCustomersCount = SUM(PurchasedCustomersCount)
FROM
(SELECT
i.brandname,
c.division,
c.route,
DivisionTotalCustomersCount =
(SELECT COUNT(distinct x.CustomerID)
FROM CustomerMaster x
WHERE x.division = c.division),
RouteTotalCustomersCount =
(SELECT COUNT(distinct x.CustomerID)
FROM CustomerMaster x
WHERE x.Route = c.route),
PurchasedCustomersCount = count(distinct C.CustomerID)
FROM CustomerMaster c
LEFT OUTER JOIN SalesData s on c.CustomerID = s.CustomerID
right outer join ItemMaster i on s.item = i.itemcode
GROUP BY i.brandname, c.division, c.route) A
GROUP BY
brandname, division, route
ORDER BY 1
Result Should as below
Excelsheet
I think you need to go reconsider the report and maybe splitting it out into multiple reports.
It does not make sense to have a route count as well as a divisional count if they are counting things at different levels of aggregation. So have a route count and division count report.
Either way, division and route is going to be null for 100PLUS because there are no customers for that brand which means there is no route or division info available.
--Division Count
SELECT BrandName, Division, COUNT(CustomerMaster.CustomerID) [Customer Count]
FROM ItemMaster LEFT OUTER JOIN
SalesData ON ItemMaster.BrandName = SalesData.Brand LEFT OUTER JOIN
CustomerMaster ON SalesData.CustomerID = CustomerMaster.CustomerID
GROUP BY BrandName, Division
--Route Count
SELECT BrandName, Route, Division, COUNT(CustomerMaster.CustomerID) [Customer Count]
FROM ItemMaster LEFT OUTER JOIN
SalesData ON ItemMaster.BrandName = SalesData.Brand LEFT OUTER JOIN
CustomerMaster ON SalesData.CustomerID = CustomerMaster.CustomerID
GROUP BY BrandName, Route, Division
Using your sqlfiddle data there are 25 sales records & 18 distinct brand/ division/ route/ customer records and there are no sales invloving 100PLUS
select
B.BrandName
, V.Division
, coalesce(Brand_count,0) as Brand_count
, coalesce(Division_count,0) as Division_count
from (select distinct BrandName from ItemMaster) as B
cross join (select distinct Division from CustomerMaster) as V
left join (
select
Brand
, Division
, sum(cust_count) over (partition by Brand) as Brand_count
, sum(cust_count) over (partition by Division) as Division_count
from (
select
S.Brand
, C.Division
, count(distinct S.CustomerID) cust_count
from salesdata as S
inner join CustomerMaster as C
on S.CustomerID = C.CustomerID
inner join ItemMaster as I
on S.item = I.ItemCode
group by
S.Brand
, C.Division
) as S
) as D
on B.BrandName = D.Brand
and V.Division = D.Division
order by
B.BrandName
, V.Division
;
| BRANDNAME | DIVISION | BRAND_COUNT | DIVISION_COUNT |
|-----------|----------|-------------|----------------|
| 100PLUS | Dubai | 0 | 0 |
| 100PLUS | RAK | 0 | 0 |
| KITCO | Dubai | 9 | 11 |
| KITCO | RAK | 9 | 7 |
| Red Bull | Dubai | 9 | 11 |
| Red Bull | RAK | 9 | 7 |
http://sqlfiddle.com/#!3/fecb0/27
All Credit to #kevriley
select
A.BrandName,
B.Division,
B.Route,
B.DivisionTotalCustomers,
B.RouteTotalCustomers,
isnull(C.PurchasedCustomersCount,0) as PurchasedCustomersCount
from
(
select distinct
BrandName, Route, Division
from dbo.ItemMaster
cross join dbo.CustomerMaster
) A
join
(
select distinct
Division,
Route,
DENSE_RANK() over (partition by Division order by c.CustomerID asc) + DENSE_RANK() over (partition by Division order by c.CustomerID desc) - 1 as DivisionTotalCustomers ,
DENSE_RANK() over (partition by ROUTE order by c.CustomerID asc) + DENSE_RANK() over (partition by ROUTE order by c.CustomerID desc) - 1 as RouteTotalCustomers
from CustomerMaster c
left join SalesData s on c.CustomerID = s.CustomerID
) B on B.Division = A.Division and B.Route = A.Route
left join
(
select
s.brand,
c.division,
c.route,
PurchasedCustomersCount = count(distinct C.CustomerID)
FROM CustomerMaster c
JOIN SalesData s on c.CustomerID = s.CustomerID
--join ItemMaster i on s.item = i.itemcode
GROUP by s.brand, c.division, c.route
) C on A.Brandname = C.Brand and C.Division = A.Division and C.Route = A.Route
See the same on SQL Fiddle
Select B.Brandname,B.Division,C AS DivisionTotalCustomerCount,
ISNULL(T.Count,0) AS PURCHASEDCUSTOMERSCOUNT
from
(
Select CM.Division,M.BrandName,COUNT(distinct CM.CustomerID) AS C
from dbo.CustomerMaster CM
CROSS JOIN ItemMaster M
GROUP BY CM.Division,M.BrandName
)B
LEFT JOIN
(Select Division,Brand,COUNT(Distinct C.CustomerID) As Count from CustomerMaster C
JOIN salesdata D
On C.CustomerID=D.CustomerID
where D.Brand='Red Bull'
GROUP BY Division,Brand
)T
ON B.Brandname=T.Brand
and B.Division=T.Division
Order by 1,2

Merging two tables into one both the table having different where clause

I am having Two Sql Queries as Follows:
1st Query
SELECT TC.TCName,
sum(BS.BLDOS) as BLDOS,
sum(BS.CollectedAmount) as CollectedAmount,
(0.35*sum(BS.BLDOS)) as TargetAmount
FROM [Customer] C
INNER JOIN [dbo].[BillingStatus] BS ON BS.CustomerID = C.CustomerID
INNER JOIN [dbo].[TCDetails] TC ON TC.CustomerID = BS.CustomerID
WHERE TC.TCName in (Select distinct(TCName)
FROM [dbo].[TCDetails] )
GROUP BY TCName
order by [TCName] ASC
I am getting a result:
||TCName || BLDOS || CollectedAmount || TargetAmount||
| Aarti | 81234.2 | 1678.76 | 789065 |
| Dev | 181234.2| 678.76 | 2389065 |
2nd query is:
SELECT COUNT(*) as count
FROM [dbo].[TCDetails]
where TCName in (Select distinct(TCName) FROM [dbo].[TCDetails] )
AND CallDate is NOT NULL
GROUP BY TCName
AND I am Getting:
||count||
231
123
I want to print it like this
||TCName || BLDOS || CollectedAmount || TargetAmount|| count ||
| Aarti | 81234.2 | 1678.76 | 789065 | 231 |
| Dev | 181234.2| 678.76 | 2389065 | 123 |
I am confused because both the queries are having different wheres clause
Try this
SELECT * FROM
(
SELECT TC.TCName, sum(BS.BLDOS) as BLDOS, sum(BS.CollectedAmount) as CollectedAmount, (0.35*sum(BS.BLDOS)) as TargetAmount
FROM [Customer] C INNER JOIN
[dbo].[BillingStatus] BS ON BS.CustomerID = C.CustomerID INNER JOIN
[dbo].[TCDetails] TC ON TC.CustomerID = BS.CustomerID
WHERE TC.TCName in (Select distinct(TCName) FROM [dbo].[TCDetails] )
GROUP BY TCName order by [TCName] ASC
) S JOIN
(
SELECT TCName,COUNT(*) as count FROM [dbo].[TCDetails]
where TCName in (Select distinct(TCName) FROM [dbo].[TCDetails] )
AND CallDate is NOT NULL GROUP BY TCName
) T ON S.TCName=T.TCName;
OP:
+--------------------------------------------------------------+
|TCName | BLDOS | CollectedAmount | TargetAmount| count |
+--------------------------------------------------------------+
| Aarti | 81234.2 | 1678.76 | 789065 | 231 |
| Dev | 181234.2| 678.76 | 2389065 | 123 |
+--------------------------------------------------------------+
In both queries you use TCDetails and group by TCName. You don't have to do this twice only to count non-null call dates. COUNT(CallDate) does that for you. I also removed the IN clause which doesn't add anthing to your query. So the query is simply:
SELECT
TC.TCName,
sum(BS.BLDOS) as BLDOS,
sum(BS.CollectedAmount) as CollectedAmount,
0.35 * sum(BS.BLDOS) as TargetAmount,
count(TC.CallDate) as cnt
FROM [Customer] C
INNER JOIN [dbo].[BillingStatus] BS ON BS.CustomerID = C.CustomerID
INNER JOIN [dbo].[TCDetails] TC ON TC.CustomerID = BS.CustomerID
GROUP BY TC.TCName
ORDER BY TC.TCName ASC;
SELECT TC.TCName, sum(BS.BLDOS) as BLDOS, sum(BS.CollectedAmount) as CollectedAmount, (0.35*sum(BS.BLDOS)) as TargetAmount ,
(SELECT COUNT(*) as count FROM [dbo].[TCDetails] TC2
where TCName in (Select distinct(TCName) FROM [dbo].[TCDetails] )
AND CallDate is NOT NULL AND TC2.TCName = TC.TCName GROUP BY TCName) AS Count
FROM [Customer] C
INNER JOIN [dbo].[BillingStatus] BS
ON BS.CustomerID = C.CustomerID
INNER JOIN [dbo].[TCDetails] TC
ON TC.CustomerID = BS.CustomerID
WHERE TC.TCName in (Select distinct(TCName) FROM [dbo].[TCDetails] )
GROUP BY TCName order by [TCName] ASC
Try as:
SELECT TC.TCName,
sum(BS.BLDOS) as BLDOS,
sum(BS.CollectedAmount) as CollectedAmount,
(0.35*sum(BS.BLDOS)) as TargetAmount,
Count(CallDate) as count
FROM [Customer] C
INNER JOIN [dbo].[BillingStatus] BS ON BS.CustomerID = C.CustomerID
INNER JOIN [dbo].[TCDetails] TC ON TC.CustomerID = BS.CustomerID
WHERE TC.TCName in (Select distinct(TCName)
FROM [dbo].[TCDetails] )
GROUP BY TCName
order by [TCName] ASC
Check Demo here.
Try below:
SELECT S.*,T.count FROM
(
SELECT TC.TCName, sum(BS.BLDOS) as BLDOS, sum(BS.CollectedAmount) as CollectedAmount, (0.35*sum(BS.BLDOS)) as TargetAmount
FROM [Customer] C JOIN
[dbo].[BillingStatus] BS ON BS.CustomerID = C.CustomerID JOIN
[dbo].[TCDetails] TC ON TC.CustomerID = BS.CustomerID
WHERE TC.TCName in (Select distinct(TCName) FROM [dbo].[TCDetails] )
GROUP BY TCName order by [TCName] ASC
) S join
(
SELECT TCName,COUNT(*) as count FROM [dbo].[TCDetails]
where TCName in (Select distinct(TCName) FROM [dbo].[TCDetails] )
AND CallDate is NOT NULL GROUP BY TCName
) T on S.TCName=T.TCName;