Select top 1 from inner join subquery - azure-data-lake

I wish to select the first value of a column in the inner join for each successful join.
#getEndDate = SELECT c.CustomerId, c.ProductId FROM #customer AS c
INNER JOIN (SELECT (DateTime?) EndDate AS EndDate, (int) CustomerId AS CustomerId
FROM #Installation
ORDER BY EndDate FETCH 1 ROW OFFSET 0 ROWS) AS i ON c.CustomerId == i.CustomerId
By doing this I get the EndDate lowest EndDate in #Installation where the join ciretia is met.
How can I get only the first value from the inner join subquery for each successful join?

You can apply the FIRST_VALUE function on INNER JOIN SELECT:
Check this:
https://learn.microsoft.com/en-us/u-sql/functions/analytic/first-value

Chose to do the following in the inner join subquery:
(SELECT (DateTime?) MAX(EndDate) AS EndDate, (int) CustomerID AS CustomerID FROM
#Installation GROUP BY CustomerID)
Works for my case.

Related

Select sum from

I am trying to get the sum of all the rows associated with each customer and join on them.
However I am finding that if no rows exist it leaves out the customer completely.
I would prefer if the sum was zero. How would I achieve this.
Here is the SQL statement:
SELECT
Id, DebitSum
FROM
Customers
JOIN
(SELECT
SUM(Amount) DebitSum, CustomerId
FROM
Purchases
WHERE
Completed IS NULL
GROUP BY
CustomerId) p ON p.CustomerId = Id;
Using SQL Server, if it matters.
Just use LEFT JOIN:
SELECT c.Id, COALESCE(p.DebitSum, 0)
FROM Customers c LEFT JOIN
(SELECT SUM(p.Amount) as DebitSum, p.CustomerId
FROM Purchases p
WHERE p.Completed IS NULL
GROUP BY CustomerId
) p
ON p.CustomerId = c.Id;
This would normally be written without the subquery:
SELECT c.Id, COALESCE(SUM(p.Amount), 0) as DebitSum
FROM Customers c LEFT JOIN
Purchases p
ON p.CustomerId = c.Id;
WHERE p.Completed IS NULL
GROUP BY c.Id
You could use LEFT JOIN:
SELECT Id, COALESCE(DebitSum,0) AS DebitSum
FROM Customers
LEFT JOIN (
SELECT SUM(Amount) DebitSum, CustomerId
FROM Purchases
WHERE Completed IS NULL
GROUP BY CustomerId
) p ON p.CustomerId = Id;
Try this:
SELECT Id, DebitSum
FROM Customers
LEFT JOIN (
SELECT SUM(Amount) DebitSum, CustomerId
FROM Purchases
WHERE Completed IS NULL
GROUP BY CustomerId
) p ON p.CustomerId = Id;
Your doing a JOIN which means it has to exist in both tables/data sets. Changing it to LEFT JOIN only requires it to be in the First table and not the one after the LEFT JOIN
You can also use subquery only:
select id, (select coalesce(sum(p.Amount), 0)
from Purchases p
where p.CustomerId = c.id and p.Completed IS NULL
) as DebitSum
from Customers c
group by id;
SELECT SUM(Amount) DebitSum, CustomerId
there is no AS after the information? select sum(amount) as debitsum, customerid
try this
SELECT c.Id, COALESCE(p.DebitSum, 0) as DebitSum
FROM Customers c LEFT JOIN Purchases p
on c.Id = p.CustomerId
where p.completed is null

Getting a SUM of the values in INNER JOIN adds up duplicate values

I am running a query which is counting the records on monthly basis from the table.
I am trying to add one extra column called "TotalPrice", I need a sum of all the prices from 'settle' table.
The problem I am facing is because of INNER JOIN, 'SUM' of the prices is adding up multiple prices due to duplicate records which the INNER JOIN is returning. Is there a way to avoid it and get a SUM of the prices from unique records ?
SELECT
CONCAT(year(datetime), '-', month(datetime)) AS YearMonth,
COUNT (DISTINCT a.id) AS TOTAL, SUM(total_price) AS TotalPrice
FROM settle AS a with (nolock)
INNER JOIN transfers b with (nolock) ON b.settleId = a.id
INNER JOIN Fdata AS c with (nolock) ON c.id= b.data
GROUP BY CONCAT(year(datetime), '-', month(datetime))
Thanks in advance.
sql server 2008 onwards:
with CTE as -- A CTE alows us to manipulate the data before we use it, like a derived table
(
select datetime, id, total_price,
row_number() over(partition by id, datetime order by total_price) as rn -- This creates a row number for each combo of id and datetime that appears
FROM settle AS a with (nolock)
INNER JOIN transfers b with (nolock) ON b.settleId = a.id
INNER JOIN Fdata AS c with (nolock) ON c.id= b.data
)
SELECT CONCAT(year(datetime), '-', month(datetime)) AS YearMonth,
COUNT (DISTINCT a.id) AS TOTAL,
SUM(total_price) AS TotalPrice
from CTE
where rn = 1 -- that row_number we created? This selects only the first one, removing duplicates
group by CONCAT(year(datetime), '-', month(datetime))

sqlerrorColumn 'tableName' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause

I have three tables
Table 1:
tblCustomer
CustomerID CustomerName
1 ABC Bank
2 Chase Bank
Table 2:
tblOrderType
OrderTypeID OrderTypeName
1 Assignment
2 LienRelease
Table 3:
tblOrder
OrderID CustomerID OrderTypeID LoanNumber
1 1 1 45584565
2 1 1 45566856
3 1 1 45565584
4 1 1 45588545
I am trying to return CustomerID, CustomerName, OrderTypeName and OrderCount in CustomerName order but when using the following query:
SELECT tblOrder.CustomerID,CustomerName,OrderTypeName,COUNT(tblOrder.CustomerID) FROM tblOrder
INNER JOIN tblCustomer ON tblOrder.CustomerID=tblCustomer.CustomerID
INNER JOIN tblOrderType ON tblOrder.OrderTypeID=tblOrderType.OrderTypeID
GROUP BY tblOrder.CustomerID
I am getting the error:
Column 'tblCustomer.CustomerName' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
I dont know what I am doing wrong.
Your SELECT and GROUP BY statements should have same fields. In your case
SELECT tblOrder.CustomerID,CustomerName,OrderTypeName
The answer is exactly what the error message is telling you.
You cannot select columns which aren't in the group by clause OR aggregated by somehow.
You also haven't included the actual order by clause.
SELECT
tblOrder.CustomerID,
tblCustomer.CustomerName,
tblOrderType.OrderTypeName,
COUNT(tblOrder.CustomerID)
FROM
tblOrder
INNER JOIN tblCustomer ON tblOrder.CustomerID=tblCustomer.CustomerID
INNER JOIN tblOrderType ON tblOrder.OrderTypeID=tblOrderType.OrderTypeID
GROUP BY
tblOrder.CustomerID,
tblCustomer.CustomerName,
tblOrderType.OrderTypeName,
ORDER BY
tblCustomer .CustomerName ASC
If you use GROUP BY in SQl-Server you have to aggregate all selected columns(f.e. with Min, Max, Count etc) or you have to include them in the GROUP BY. That makes sense because it's not clear which row's value you want to take for CustomerName and OrderTypeName, there could be multiple for each id-group.
If that's not the case include it in the Group by:
SELECT tblOrder.CustomerID,
CustomerName,
OrderTypeName,
COUNT(tblOrder.CustomerID) As CountCustomerID
FROM tblOrder
INNER JOIN tblCustomer ON tblOrder.CustomerID=tblCustomer.CustomerID
INNER JOIN tblOrderType ON tblOrder.OrderTypeID=tblOrderType.OrderTypeID
GROUP BY tblOrder.CustomerID, CustomerName, OrderTypeName
Another way in SQL-Server(>=2005) is using a CTE(or subquery) + ROW_NUMBER, then you can select all fields:
WITH CTE AS
(
SELECT tblOrder.CustomerID,
CustomerName,
OrderTypeName,
Count(*) OVER (PARTITION BY tblOrder.CustomerID, CustomerName, OrderTypeName),
RN = ROW_NUMBER() OVER (PARTITION BY tblOrder.CustomerID, CustomerName, OrderTypeName
ORDER BY CustomerID, CustomerName)
FROM tblOrder
INNER JOIN tblCustomer ON tblOrder.CustomerID=tblCustomer.CustomerID
INNER JOIN tblOrderType ON tblOrder.OrderTypeID=tblOrderType.OrderTypeID
)
SELECT * FROM CTE
WHERE RN = 1
You need to aggregate the columns that are not included in your GROUP BY statement:
SELECT A.CUSTOMERID, MAX(B.CUSTOMERNAME), MAX(C.ORDERTYPENAME), COUNT(A.CUSTOMERID)
FROM TBLORDER AS A
INNER JOIN TBLCUSTOMER AS B
ON A.CUSTOMERID=B.CUSTOMERID
INNER JOIN TBLORDERTYPE AS C
ON A.ORDERTYPEID=C.ORDERTYPEID
GROUP BY A.CUSTOMERID
Or you can group by the same columns in your SELECT.
Something like this
SELECT tblOrder.CustomerID, CustomerName, OrderTypeName, COUNT(*)
FROM tblOrder
INNER JOIN tblCustomer ON tblOrder.CustomerID=tblCustomer.CustomerID
INNER JOIN tblOrderType ON tblOrder.OrderTypeID=tblOrderType.OrderTypeID
GROUP BY tblOrder.CustomerID, CustomerName, OrderTypeName
or this
SELECT tblOrder.CustomerID, CustomerName, COUNT(*)
FROM tblOrder
INNER JOIN tblCustomer ON tblOrder.CustomerID = tblCustomer.CustomerID
GROUP BY tblOrder.CustomerID, CustomerName

Getting individual counts of last three distinct rows in column of data retrieved from multiple tables

I have a query which returns several rows of data (in datetime format) of a single column obtained by performing JOINS on multiple SQL Tables. The Data obtained is a DateTime type and now I just want the individual count of latest three dates probably the count of lat three distinct dates as it sorted from earliest to latest.
SQL Query
SELECT
ST.EffectiveDate
FROM Person.Contact C
INNER JOIN Sales.SalesPerson SP
ON C.ContactID = SP.SalesPersonID
FULL OUTER JOIN Sales.SalesTerritory ST
ON ST.TerritoryID = SP.TerritoryID
The above query returns around 200 rows of data but I want the count for each of three latest dates possibly bottom three
I would do this with top and group by:
SELECT TOP 3 ST.EffectiveDate, COUNT(*) as cnt
FROM Person.Contact C INNER JOIN
Sales.SalesPerson SP
ON C.ContactID = SP.SalesPersonID FULL OUTER JOIN
Sales.SalesTerritory ST
ON ST.TerritoryID = SP.TerritoryID
GROUP BY ST.EffectiveDate
ORDER BY ST.EffectiveDate DESC
added another query to get the latest 3 distinct dates
SELECT count(1)
FROM Person.Contact C
INNER JOIN Sales.SalesPerson SP
ON C.ContactID = SP.SalesPersonID
FULL OUTER JOIN Sales.SalesTerritory ST
ON ST.TerritoryID = SP.TerritoryID
WHERE ST.effectivedate in (select distinct top 3 effectivedate
from salesterritory
order by effectivedate desc)
Or if you need to see the counts for the 3 dates broken out
SELECT st.effectivedate, count(1)
FROM Person.Contact C
INNER JOIN Sales.SalesPerson SP
ON C.ContactID = SP.SalesPersonID
FULL OUTER JOIN Sales.SalesTerritory ST
ON ST.TerritoryID = SP.TerritoryID
WHERE ST.effctivedate in (select distinct top 3 effectivedate
from salesterritory
order by effectivedate desc)
GROUP BY st.effectivedate
You can also use the analytic RANK function. This query will number the latest date as 1, the next latest as 2, and so forth:
SELECT
ST.EffectiveDate,
ROW_NUMBER() OVER (ORDER BY ST.EffectiveDate DESC) AS DateRank
FROM Person.Contact C
INNER JOIN Sales.SalesPerson SP ON C.ContactID = SP.SalesPersonID
FULL OUTER JOIN Sales.SalesTerritory ST ON ST.TerritoryID = SP.TerritoryID
You can't use the ranked value in the WHERE clause, so you'll need to take the query above and make it a subquery or a common table expression (CTE).
Subquery version:
SELECT EffectiveDate, COUNT(*)
FROM (
SELECT
ST.EffectiveDate,
ROW_NUMBER() OVER (ORDER BY ST.EffectiveDate DESC) AS DateRank
FROM Person.Contact C
INNER JOIN Sales.SalesPerson SP ON C.ContactID = SP.SalesPersonID
FULL OUTER JOIN Sales.SalesTerritory ST ON ST.TerritoryID = SP.TerritoryID
) DateList
WHERE DateRank <= 3
GROUP BY EffectiveDate
CTE version:
WITH DateList AS (
SELECT
ST.EffectiveDate,
ROW_NUMBER() OVER (ORDER BY ST.EffectiveDate DESC) AS DateRank
FROM Person.Contact C
INNER JOIN Sales.SalesPerson SP ON C.ContactID = SP.SalesPersonID
FULL OUTER JOIN Sales.SalesTerritory ST ON ST.TerritoryID = SP.TerritoryID
)
SELECT EffectiveDate, COUNT(*)
FROM DateList
WHERE DateRank <= 3
GROUP BY EffectiveDate
If you're dealing SQL Server 2005 and above, you could even try this:
;with cte as
(
SELECT
ST.EffectiveDate
FROM Person.Contact C
INNER JOIN Sales.SalesPerson SP
ON C.ContactID = SP.SalesPersonID
FULL OUTER JOIN Sales.SalesTerritory ST
ON ST.TerritoryID = SP.TerritoryID
)
Select EffectiveDate, count(1)
from cte
where EffectiveDate in (select distinct top 3 effectivedate
from cte
order by EffectiveDate desc)
group by EffectiveDate
Though untested, it should work; it my be unnecessarily elaborate though.

sql query with two tables having reference key

I have two tables:
Discounts(disid primary key)
Cust(custid primary key, disid ref discount(disid))
Now I need a query to get custid having all disid(discount coupons) and the customer may contain the same disid more than once.
select custid, count(distinct disid) from cust
group by custid
having count(*) = (select count(*) from discounts)
SELECT COUNT(DISTINCT D.disid) FROM CUST C
INNER JOIN DISCOUNTS D ON D.disid=C.disid GROUP BY D.disid
try either of this solutions:
SELECT a.custid, COUNT(a.disid) totalCoupon
FROM cust a
INNER JOIN discounts b
ON b.disid = a.disid
GROUP BY a.custid
or
SELECT a.custid, COUNT(a.disid) totalCoupon
FROM cust a
INNER JOIN discounts b
ON b.disid = a.disid
GROUP BY a.custid
HAVING COUNT(a.disid) > 1 -- customers having the same (but more than 1)
-- CouponID will only be shown here