How To Get Single Column Result From SqlServer Query Using Group By - sql-server

I have two classic tables (OK, not my real problem). Orders and OrderItems. I want to using a single statement to delete all Orders that have no OrderItems. I can get the list of Orders I want to delete with a query like this:
SELECT COUNT(*),OrderId
FROM OrderItems
GROUP BY OrderId
HAVING COUNT(*) > 0
and what I want to do is something like:
DELETE FROM Orders WHERE Id NOT IN (....)
Where "...." is my SELECT above. The select is giving me two columns and I really don't want the second column, just the first.
I feel like there is some kind of self join, or something like that I can use but I'm read only when it comes to that.

DELETE from Orders Where Id NOT IN (SELECT OrderId
FROM OrderItems
GROUP BY OrderId
HAVING COUNT(*) >0);

Related

SQL Server random rows on where clause

I need to select 10 random rows from a table, but it has to be done in the where clause, because the query is executed using another aplication that only allows to modify this part.
I searched for a lot of solutions (select top 10, RAND(), ORDER BY NEWID(), ...), but none work in the where clause.
There an option to do that? or some kind of workaround?
Try this:
SELECT *
FROM Test
WHERE Id IN (SELECT TOP 10 Id FROM Test ORDER BY NewId())
If your table has a unique column you can do something like :
SELECT * FROM TABLE WHERE PRIMARYCOLUMN IN (SELECT TOP(10) PRIMARYCOLUMN FROM TABLE ORDER BY NEWID())

SQL Aggregate function issues using DISTINCT function

I'm needing help with a question that I've been racking my brain on for two days now (Almost), on this assignment. I'm still pretty new to SQL and I'm just struggling.
I DO NOT WANT THE ANSWER!! I'm just looking for help getting going in the right direction.
Here is the question:
Write a SELECT statement that answers this question: Which customers have ordered more than one product? Return these columns:
The email address from the Customers table
The count of distinct products from the customer’s orders
Here is what I have so far:
SELECT Customers.CustomerID,
Count(DISTINCT ProductID) AS ProductsCount
FROM Customers
INNER JOIN Orders
ON Customers.CustomerID = Orders.CustomerID
JOIN Products
ON Products.ProductID = OrderItems.ProductID
GROUP BY Customers.CustomerID,
Orders.CustomerID
But I keep getting this error:
Msg 4104, Level 16, State 1, Line 2
The multi-part identifier "OrderItems.ProductID" could not be bound.
The structure of the three tables in play here is.
The Customer table has an Emailaddress and CustomerID column.
The Orders table has CustomerID and OrderID columns.
The Products table has ProductID column.
The OrderItems table has OrderID, ProductID, and Quantity columns.
Any Help would be really really helpful!
Thanks!
Fix the syntax as suggested by joining to the OrderItems table and in order to look for something more than once, you need to use group by field1, field2, etc. having count(field) > 1. You are almost there.
You are almost there :-)
You forgot to join OrderItems.
You don't need the table Products in this query (you don't want to see anything from that table; you get the product count from OrderItems).
To limit by aggregates (as by the number of products here) use HAVING.
To group by Orders.CustomerID is superfluous, as it equals Customers.CustomerID.
Here is a tip to find the answer,
find the orders which has has more than one item in OrderItems
table by using having clause with Count() aggregate and Group by orderID.
so from the first step you will have the orders that have more than
one item and count of products in every order. next join the first step result with
order table to get the customerid.
next join the second step result with customers table to get the
customers information who bought more than one one product in single
order with count.

IS NOT NULL on as statement

I have two tables called 'teacher' and 'courses'. Table 'teachers' has four columns i.e. teacher_id, teacher_name, teacher_work_hours and course_id. Table 'courses' has two columns i.e. course_id and course_name. I want to select two columns from table 'teacher' and count the number of instances in table 'courses' for which teacher.course_id = course.course_id. The query should discard the rows where the count() for table course is zero i.e. the the rows for which count() is zero should not show up in the resultset. How do I do that?
I have this query.
select t.teacher_name, t.teacher_work_hours, (select count(*)
from course where course_id = t.course_id
having count(*) > 0) as COURSES
from teacher t
where teacher_work_hours > 5
AND COURSES IS NOT NULL
The query is incorrect as it doesn't let me put IS NOT NULL operator on COURSES.
ROLES is a table rather than a column, and anyway it only appears within the subquery. Would this not make more sense? (This still won't work, because you can't use the alias in the WHERE clause, but it is closer to making sense.)
SELECT name, class, (SELECT COUNT(*)
FROM xyz
-- HAVING COUNT(*) > 0
-- Doesn't make sense without a GROUP BY
) AS ROLES
FROM abc
WHERE class > 5
AND ROLES IS NOT NULL
I don't think this is what you actually want to do, though, because the subquery doesn't depend upon the current row of abc. You probably need to change the query to use a join and a GROUP BY instead of a subquery.
Query is not clear. But I just wanted to share the following query for your reference. Please do check the query whether it is useful...
SELECT class, ROLES.Total
FROM abc
CROSS APPLY
(SELECT COUNT(*) AS Total FROM xyz WHERE abc.class = xyz.class) ROLES
WHERE class > 5

SQL WHERE NOT EXISTS (skip duplicates)

Hello I'm struggling to get the query below right. What I want is to return rows with unique names and surnames. What I get is all rows with duplicates
This is my sql
DECLARE #tmp AS TABLE (Name VARCHAR(100), Surname VARCHAR(100))
INSERT INTO #tmp
SELECT CustomerName,CustomerSurname FROM Customers
WHERE
NOT EXISTS
(SELECT Name,Surname
FROM #tmp
WHERE Name=CustomerName
AND ID Surname=CustomerSurname
GROUP BY Name,Surname )
Please can someone point me in the right direction here.
//Desperate (I tried without GROUP BY as well but get same result)
DISTINCT would do the trick.
SELECT DISTINCT CustomerName, CustomerSurname
FROM Customers
Demo
If you only want the records that really don't have duplicates (as opposed to getting duplicates represented as a single record) you could use GROUP BY and HAVING:
SELECT CustomerName, CustomerSurname
FROM Customers
GROUP BY CustomerName, CustomerSurname
HAVING COUNT(*) = 1
Demo
First, I thought that #David answer is what you want. But rereading your comments, perhaps you want all combinations of Names and Surnames:
SELECT n.CustomerName, s.CustomerSurname
FROM
( SELECT DISTINCT CustomerName
FROM Customers
) AS n
CROSS JOIN
( SELECT DISTINCT CustomerSurname
FROM Customers
) AS s ;
Are you doing that while your #Tmp table is still empty?
If so: your entire "select" is fully evaluated before the "insert" statement, it doesn't do "run the query and add one row, insert the row, run the query and get another row, insert the row, etc."
If you want to insert unique Customers only, use that same "Customer" table in your not exists clause
SELECT c.CustomerName,c.CustomerSurname FROM Customers c
WHERE
NOT EXISTS
(SELECT 1
FROM Customers c1
WHERE c.CustomerName = c1.CustomerName
AND c.CustomerSurname = c1.CustomerSurname
AND c.Id <> c1.Id)
If you want to insert a unique set of customers, use "distinct"
Typically, if you're doing a WHERE NOT EXISTS or WHERE EXISTS, or WHERE NOT IN subquery,
you should use what is called a "correlated subquery", as in ypercube's answer above, where table aliases are used for both inside and outside tables (where inside table is joined to outside table). ypercube gave a good example.
And often, NOT EXISTS is preferred over NOT IN (unless the WHERE NOT IN is selecting from a totally unrelated table that you can't join on.)
Sometimes if you're tempted to do a WHERE EXISTS (SELECT from a small table with no duplicate values in column), you could also do the same thing by joining the main query with that table on the column you want in the EXISTS. Not always the best or safest solution, might make query slower if there are many rows in that table and could cause many duplicate rows if there are dup values for that column in the joined table -- in which case you'd have to add DISTINCT to the main query, which causes it to SORT the data on all columns.
-- Not efficient at all.
And, similarly, the WHERE NOT IN or NOT EXISTS correlated subqueries can be accomplished (and give the exact same execution plan) if you LEFT OUTER JOIN the table you were going to subquery -- and add a WHERE . IS NULL.
You have to be careful using that, but you don't need a DISTINCT. Frankly, I prefer to use the WHERE NOT IN subqueries or NOT EXISTS correlated subqueries, because the syntax makes the intention clear and it's hard to go wrong.
And you do not need a DISTINCT in the SELECT inside such subqueries (correlated or not). It would be a waste of processing (and for WHERE EXISTS or WHERE IN subqueries, the SQL optimizer would ignore it anyway and just use the first value that matched for each row in the outer query). (Hope that makes sense.)

Unable to understand the SQL code

I am finding it difficult to understand the code below. Can you give me a logical flow of how the code works ?
The question -
suppose you want to display the total number of orders placed by every customer in your Customers table. Orders are stored in the Orders table along with the appropriate customer ID.
The steps -
retrieve the list of customers from the customers table.
for each customer retrieved, count the number of associated orders in the Orders table.
The solution -
SELECT cust_name, cust_state,
(SELECT COUNT(*)
FROM Orders
WHERE Orders.cust_id = Customers.cust_id
)
AS order_nos
FROM Customers
ORDER BY cust_name
I am unable to understand the count(*) part inside the brackets. Please help me to figure it out.
Thanks.
It's just counting the number of rows. In this case, that's the number of orders per customer. The alternative COUNT(column_name) gives you the number of rows where column_name isn't null.
Equivalent without the sub-query (using a group instead):
SELECT cust_name, cust_state, COUNT(orders.cust_id) order_nos
FROM Customers
LEFT OUTER JOIN Orders on Customers.cust_id = Orders.cust_id
GROUP BY cust_name, cust_state
ORDER BY cust_name
It's called a correlated subquery. Essentially, for each customer, you're going to get a count of how many orders that customer has. The "magic" is in the WHERE Orders.cust_id = Customers.cust_id clause in the subquery. That's the part that correlates this result to your main query. It's saying "take the cust_id from the main query and now find the count of orders where the cust_id is that cust_id".

Resources