Question
I have a query and would like to join one column from another table based on its matching ID
Query So far
SELECT DENumber, AcquiredDate, ItemDescription, ItemName, LocationID FROM dbo.Assets JOIN LocationName FROM dbo.Locations on ProductID
WHERE DATEDIFF(YEAR, AcquiredDate, GetDate()) >= 6
The matching ID in both tables is LocationID
Problem
My query is wrong and throws errors
Msg 156, Level 15, State 1, Line 1
Incorrect syntax near the keyword 'FROM'.
Rewrite your query to this:
SELECT DENumber, AcquiredDate, ItemDescription, ItemName, LocationName
FROM dbo.Assets INNER JOIN dbo.Locations ON Assets.LocationId = Locations.LocationId
WHERE DATEDIFF(YEAR, AcquiredDate, GetDate()) >= 6
To clarify: In a JOIN, you must specify the names of both tables on either side of the JOIN keyword. Then, you specify the join criteria after the ON keyword:
FROM <<table1>> INNER JOIN <<table2>> ON <<join criteria>>
Here, we only want records that exist in both tables, which is why we use the INNER join, but you can also take all records from either the LEFT table, the RIGHT table or BOTH tables. In that case, you would do a LEFT JOIN, RIGHT JOIN our OUTER JOIN respectively.
SELECT L.DENumber, A.AcquiredDate, A.ItemDescription, A.ItemName, L.LocationID
FROM dbo.Assets A JOIN
ON dbo.Locations L on
L.ProductID = A.ProductID
WHERE DATEDIFF(YEAR, A.AcquiredDate, GetDate()) >= 6
Related
This question already has answers here:
Reason for Column is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause [duplicate]
(4 answers)
Closed 11 months ago.
I have two TABLES as customers$ and orders$ (I am not sure why there is a $ sign after the table name. It appears in my Microsoft SQL Server Management Studio every time I import the excel file).
customer$ table has 2 columns = name(nvarchar(255,null) | customer_id(float,null)
orders$ table has 4 columns = order_id(nvarchar(255,null) | customer_id | status(nvarchar(255,null) | order_date(datetime, null)
My statement is to count the number of orders per customer
SELECT c.name,c.customer_id AS CustomerID,o.customer_id AS OcustomerID, COUNT(*) AS Number_of_orders
FROM customers$ c, orders$ o
WHERE c.customer_id = o.customer_id
GROUP BY name
ORDER BY Number_of_orders
OUTPUT:
Msg 8120, Level 16, State 1, Line 1
Column 'customers$.customer_id' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
When you use an aggregate function (like COUNT, SUM, AVG, etc.), any field that is not aggregated must be listed in the GROUP BY clause:
SELECT c.name, c.customer_id AS CustomerID, COUNT(*) AS Number_of_orders
FROM customers$ c
INNER JOIN orders$ o ON c.customer_id = o.customer_id
WHERE c.customer_id = o.customer_id
GROUP BY c.name, c.customer_id
ORDER BY Number_of_orders
You also don't need o.customer_id. The join condition make sure that c.customer_id and o.customer_id are identical.
Also, avoid the old join syntax:
FROM tableA, tableB
WHERE tableA.column = tableB.column
Replace it with INNER JOIN:
FROM tableA
INNER JOIN tableB ON tableA.column = tableB.column
You probably want to do either an in-line select
SELECT c.name,c.customer_id AS CustomerID, (select COUNT(*) FROM orders$ o c.customer_id = o.customer_id) AS Number_of_orders
ORDER BY Number_of_orders
or you need to add c.customer_id to your Group By. Also no point in selecting o.Customer_id as that should be identical to c.customer_id
SELECT c.name,c.customer_id AS CustomerID, COUNT(*) AS Number_of_orders
FROM customers$ c, orders$ o
WHERE c.customer_id = o.customer_id
GROUP BY name, c.customer_id
ORDER BY Number_of_order
i have a inner join query in stored procedure which is working fine. i need to inject a aggregate query in it so that it show an aggregated result in a new column
https://drive.google.com/file/d/1tAIEACvEnG7sAisSoE2crYRrzCjIcvST/view?usp=sharing
i tried to inject aggregate query as a column TotalQty in my query
SELECT dbo.SO.Id,dbo.Customer.Name, dbo.Product.Name AS ProductName, dbo.SOD.SalePrice
,TotalQty = (select SUM(dbo.SOD.Quantity) from [sod] o where o.SOId='68BD0F69-B957-439F-9AD0-180DF23EF42B' )
FROM dbo.SOD INNER JOIN
dbo.Product ON dbo.SOD.ProductId = dbo.Product.Id RIGHT JOIN
dbo.SO ON dbo.SOD.SOId = dbo.SO.Id INNER JOIN
dbo.Customer ON dbo.SO.CustomerId = dbo.Customer.Id
WHERE (dbo.SO.Id = '68BD0F69-B957-439F-9AD0-180DF23EF42B')
But it says
Column 'dbo.SO.Id' is invalid in the select list because it is not
contained in either an aggregate function or the GROUP BY clause.
or any other good Technique suggested will be appreciated.
so change AS :
SELECT dbo.SO.Id,dbo.Customer.Name, dbo.Product.Name AS ProductName, dbo.SOD.SalePrice
,(select count(dbo.SOD.Quantity) from [sod] o where o.SOId='68BD0F69-B957-439F-9AD0-180DF23EF42B') AS TotalQty
FROM dbo.SOD INNER JOIN
dbo.Product ON dbo.SOD.ProductId = dbo.Product.Id RIGHT JOIN
dbo.SO ON dbo.SOD.SOId = dbo.SO.Id INNER JOIN
dbo.Customer ON dbo.SO.CustomerId = dbo.Customer.Id
WHERE (dbo.SO.Id = '68BD0F69-B957-439F-9AD0-180DF23EF42B')
As in the internal query, your characteristic is you used the o.SOId field on where and in other hand used count aggregate function so you should:
SELECT dbo.SO.Id,dbo.Customer.Name, dbo.Product.Name AS ProductName,
dbo.SOD.SalePrice
,count(dbo.SOD.Quantity) AS TotalQty
FROM dbo.SOD INNER JOIN
dbo.Product ON dbo.SOD.ProductId = dbo.Product.Id RIGHT JOIN
dbo.SO ON dbo.SOD.SOId = dbo.SO.Id INNER JOIN
dbo.Customer ON dbo.SO.CustomerId = dbo.Customer.Id
WHERE (dbo.SO.Id = '68BD0F69-B957-439F-9AD0-180DF23EF42B')
group by
dbo.SO.Id,dbo.Customer.Name, dbo.Product.Name , dbo.SOD.SalePrice
Which will have the same output.
Generally speaking, you encourage others to help if you provide a MVCE. Using cryptic table names (are they tables? or views perhaps?) is not a healthy practice. In addition, it is not clear what you are trying to achieve with your subquery. You attempted to use count but you label the value as "TotalQty" and you replied to a suggestion using "sum". Very confusing.
So since we don't have your tables, I used the common MS sample database AdventureWorks. Below are two examples of counting the quantity values from the detail table.
select Ord.SalesOrderID, Det.SalesOrderDetailID,
Cust.AccountNumber as CustName, -- too lazy to get actual name
Prd.Name as ProductName,
Det.UnitPrice
,Counted.TotalQty
-- TotalQty = (select count(dbo.SOD.Quantity) from [sod] o where o.SOId='68BD0F69-B957-439F-9AD0-180DF23EF42B' )
from Sales.SalesOrderHeader as Ord
inner join Sales.SalesOrderDetail as Det on Ord.SalesOrderID = Det.SalesOrderID
inner join Production.Product as Prd on Det.ProductID = Prd.ProductID
inner join Sales.Customer as Cust on Ord.CustomerID = Cust.CustomerID
cross apply (select count(DetCnt.OrderQty) as TotalQty from Sales.SalesOrderDetail as DetCnt where DetCnt.SalesOrderID = Det.SalesOrderID) as Counted
where Ord.SalesOrderID = 43659
select Ord.SalesOrderID, Det.SalesOrderDetailID,
Cust.AccountNumber as CustName, -- too lazy to get actual name
Prd.Name as ProductName,
Det.UnitPrice
, TotalQty = (select count(DetCnt.OrderQty) from Sales.SalesOrderDetail as DetCnt where DetCnt.SalesOrderID = Det.SalesOrderID)
-- TotalQty = (select count(dbo.SOD.Quantity) from [sod] o where o.SOId='68BD0F69-B957-439F-9AD0-180DF23EF42B' )
from Sales.SalesOrderHeader as Ord
inner join Sales.SalesOrderDetail as Det on Ord.SalesOrderID = Det.SalesOrderID
inner join Production.Product as Prd on Det.ProductID = Prd.ProductID
inner join Sales.Customer as Cust on Ord.CustomerID = Cust.CustomerID
where Ord.SalesOrderID = 43659
I think that interpretation is correct but I don't know your schema. I added the PK of the detail table to help "see" the relationship between Order and Detail.
Examine the code closely. Notice how the query only refers to the specific PK value once (this would be your procedure's parameter). You use correlations and joins to limit the results as needed. And notice how much easier it is to understand the query since it uses names that are actual words - SalesOrder vs. SO. I don't think it makes much sense to right join your Detail table to the Order table - seems like a mistake. Your aggregation attempt is odd so I can't say if the value computed by these queries is correct.
I'll also note that you should not be passing the PK value of your table using a nvarchar parameter. Use the correct datatype to avoid the possibility that someone attempts to pass an actual string (e.g., N'Pick me') instead of a GUID value.
I have a little problem with some query.
This is the task:
Create a query that displays the employees with no sale in the last 3 months to customers who are from "USA".
This is what i wrote:
Select emp.EmployeeID, (emp.FirstName + ' ' + emp.LastName) AS Name
From Employees AS emp
Join Orders AS o ON emp.EmployeeID = o.EmployeeID
Join Customers AS c ON o.CustomerID = c.CustomerID
Where c.Country LIKE 'USA';
One of the problem is that i don't know where to put this select query (it's for calculating the last 3 months but i'm not sure that this is true):
Select DATEDIFF(MM, '1998-02-01', '1998-05-31') From Orders
The second problem is that i don't have an idea for the part "employees with no sale" How can i find this?
Should i use other kind of joins or something else?
Sorry for my question but i'm new in SQL and i'll appreciate any kind of help.
If you have any questions, please ask. :)
Create a query that displays the employees with no sale in the last 3 months to customers who are from "USA"
Select * From Employees e
Where not exists
(Select * from orders o join customers c
on c.CustomerID = o.CustomerID
Where c.Country = "USA"
and o.saleDate >= DateAdd(month, -3, getdate()))
How you actually treat "last 3 months" depends on you, but this is one way to approach the task:
select e.*
from employees e
where not exists (
select 1
from orders o
join customers c on c.customerid = o.customerid
where e.employeeid = o.employeeid
and c.country = 'USA'
and c.orderdate > dateadd(month, datediff(month, 0, getdate()), 3)
);
Last three months could mean months per se or just days that make exactly last three months (eg. 91)
If you're just learning SQL, please don't take one of these answers and use it to do your homework. You'll need to figure out what's going on for yourself.
Try to take this task in pieces. First, let's look at 'customers from USA.' You can probably write this one yourself:
Select * from customers where country = 'usa'
Next, consider how to find the orders for those customers (all of them, for now).
Since you've posted an example of an inner join, I'm going to assume you could write that one yourself, too:
Select o.* from customers c inner join orders o on
c.customerID = o.customerID
where country = 'usa'
Now you've asked where/how to apply the criteria for 'sales in the last 3 months.' Note each order has an orderDate, representing the date the order was placed. You need to use the order table's orderdate field with today's date and compare the number of months between them. The getdate() function returns the date and time from the server. Try executing:
select getdate()
then you can experiment with the datediff() function on the orderDates in the orders table:
Select orderid, getdate(), orderdate, datediff(mm,orderdate,getdate())
from orders
I think you'll have better luck, though, adding 3 months to orderdate and comparing with getdate():
Select orderid, orderdate, dateadd(month, orderdate, 3),
getdate(), dateadd(month, getdate(), -3)
from orders
Now you can see all the employee IDs you don't want, the ones that have orders within the last 3 months, and you already know how to limit orders by customers in USA. Those are the IDs you want to exclude from the employees table. You can do that in a couple of different ways, depending on what you've learned so far, but typically you're exposed to LEFT OUTER JOINs for this sort of thing. You'll want to left outer join your employee table with the set of IDs you don't want (the ones with orders in the past 3 months) on the employeeID field, and return rows where the employeeID from the order subquery is null.
Try:
select count(*) from employees -- note rowcount
then:
select min(employeeID) from orders -- pick one employee
then:
select count(e.employeeID)
from employees e left outer join
(select * from orders
where employeeID in (select min(employeeID) from orders)
) o on e.employeeID = o.employeeID
where o.employeeID is null
this count should be one less than the total number of rows in your employees table, it should exclude the lowest employeeID with an order.
Then see if you can figure out how to do your homework.
Left/Right joins exist as well and you can somewhat think of them as Venn diagrams (Join or Inner Join is the intersect, Left Join is intersect and left circle, etc.). Its one perspective on how to think what will be returned. Fields returned which are not in the intersect like with a Left Join will be NULL.
The below is another way to do it:
Select emp.EmployeeID, (emp.FirstName + ' ' + emp.LastName) AS Name
From Employees AS emp
Left Join Orders As o ON emp.EmployeeID = o.EmployeeID
And o.OrderDate > DateAdd(month,-3,GetDate())
Join Customers AS c ON o.CustomerID = c.CustomerID
Where c.Country = 'USA' And o.EmployeeID is Null
Group By emp.EmployeeID, emp.FirstName, emp.LastName;
I am still extremely new at SQL and have recently been having issues with these 3 specific subqueries for several days.
This one is supposed to return 3 columns, only returns records of vendors from "CA" and uses a derived table.
-- Query 6
SELECT VendorID, VendorName, Vendors.VendorState
FROM Vendors
JOIN (SELECT VendorState
FROM Vendors) AS SubVendors ON Vendors.VendorID = SubVendors.VendorID
WHERE Vendors.VendorState = 'CA'
ORDER BY VendorID;
But when I run it, I get this error:
Msg 207, Level 16, State 1, Line 6
Invalid column name 'VendorID'.
This one returns 4 columns, also uses a derived table and the subquery is coded in the 'FROM' clause.
-- Query 7
SELECT
InvoicesMain.VendorID,
MAX(InvoiceTotal) AS MaxInvoice,
MIN(InvoiceTotal) AS MinInvoice,
AVG(InvoiceTotal) AS AvgInvoice
FROM
Invoices AS InvoiceMain
JOIN
(SELECT TOP 10
VendorID, AVG(InvoiceTotal) AS AvgInvoice
FROM Invoices
GROUP BY VendorID
ORDER BY AvgInvoice DESC) AS TopVendor ON InvoicesMain.VendorID = TopVendor.VendorID)
GROUP
InvoicesMain.VendorID
ORDER BY
MaxInvoice DESC;
But I get this error:
Msg 102, Level 15, State 1, Line 9
Incorrect syntax near ')'.
And lastly, I am honestly not sure how to do this one; it is supposed to be restated as a subquery:
SELECT
InvoiceNumber, InvoiceDate, InvoiceLineItemAmount
FROM
Invoices
JOIN
InvoiceLineItems ON Invoices.InvoiceID = Invoicelineitems.InvoiceID
WHERE
VendorID = 122
ORDER BY
InvoiceDate;
Any tips, please?
On Query 6, you didn't select the VendorID on your subquery, that's why the error occurred. Try this query instead:
SELECT VendorID, VendorName, Vendors.VendorState
FROM Vendors JOIN
(SELECT VendorState, VendorID
FROM Vendors) AS SubVendors
ON Vendors.VendorID = SubVendors.VendorID
WHERE V.VendorState = 'CA'
ORDER BY VendorID;
For Query 7 you are just missing a ) on your subquery.
SELECT InvoicesMain.VendorID, MAX(InvoiceTotal) AS MaxInvoice, MIN(InvoiceTotal) AS MinInvoice, AVG(InvoiceTotal) AS AvgInvoice
FROM Invoices AS InvoiceMain
JOIN
(SELECT TOP 10 VendorID, AVG(InvoiceTotal)) AS AvgInvoice
FROM Invoices
GROUP BY VendorID
ORDER BY AvgInvoice DESC) AS TopVendor
ON InvoicesMain.VendorID = TopVendor.VendorID)
GROUP InvoicesMain.VendorID
ORDER BY MaxInvoice DESC;
For the last item, you can reinstate this as subquery by selecting InvoiceID from the table InvoiceLineItems just like in Query 6
SELECT InvoiceNumber, InvoiceDate, InvoiceLineItemAmount
FROM Invoices JOIN
(SELECT InvoiceID FROM Invoicelineitems) As I
ON Invoices.InvoiceID = I.InvoiceID
WHERE VendorID = 122
ORDER BY InvoiceDate;
Im trying to select from 2 tables that have the same columns, but both tables have an inner join -
select e.ID,
c.FullName,
car.VIN,
car.Registration,
e.Telephone,
e.Mobile,
e.Email,
e.EstimateTotal,
e.LastUpdated,
e.LastUpdateBy from (select id from Estimates UNION ALL select id from PrivateEstimates) e
inner join Customers c on c.ID = e.CustomerID
inner join Cars car on car.ID = e.CarID
where e.Status = 0
The trouble is, it can't find e.CustomerID, e.CarID or e.Status on the inner join? Any ideas?
Your subquery
select id from Estimates
union all
select id from PrivateEstimates
returns only a single id column. Include necessary columns in the subquery if you want to use those columns in JOIN statements