Un Ordered Customer - mysql

I have two tables fist one customer and second one Orderdetails. I want list of sign ups from 4th on wards and exclude the list of customers who have bought.
SELECT *
FROM Customer
WHERE RegisteredDate BETWEEN CONVERT(DATETIME,CONVERT(VARCHAR(50),'12/04/2015',101))
AND CONVERT(DATETIME,CONVERT(VARCHAR(50),'12/07/2015',101))
AND CustomerID NOT IN(SELECT *
FROM Customer c
INNER JOIN orderdetails od ON c.CustomerId = od.CustomerID
WHERE C.RegisteredDate
BETWEEN CONVERT(DATETIME,CONVERT(VARCHAR(50),'12/04/2015',101))
AND CONVERT(DATETIME,CONVERT(VARCHAR(50),'12/07/2015',101))
AND Transactionid IS NOT NULL
)
the result is:
Msg 116, Level 16, State 1, Line 13 Only one expression can be
specified in the select list when the subquery is not introduced with
EXISTS.

Remove * (all columns) in subquery and specify select CustomerID instead of *(all columns) in subquery.
Because when using NOT IN, it is expected that the number of columns return by the subquery is only one.

As mentioned in other answer IN operator only expects one column to be returned when being used with a sub-query, you should only select the cutomerID in the sub-query but if there is a chance of it returning NULL values then use EXISTS operator something like....
SELECT *
FROM Customer c1
WHERE RegisteredDate BETWEEN CONVERT(DATETIME,'12/04/2015',101)
AND CONVERT(DATETIME,'12/07/2015',101)
AND NOT EXISTS (SELECT *
FROM Customer c
INNER JOIN orderdetails od ON c.CustomerId = od.CustomerID
WHERE C.RegisteredDate
BETWEEN CONVERT(DATETIME,'12/04/2015',101)
AND CONVERT(DATETIME,'12/07/2015',101)
AND Transactionid IS NOT NULL
AND C1.CustomerID = c.CustomerID
)

You cant use select * in a subquery, you need to specify the column which in this case is customerid.
SELECT *
FROM Customer
WHERE RegisteredDate BETWEEN CONVERT(DATETIME,CONVERT(VARCHAR(50),'12/04/2015',101))
AND CONVERT(DATETIME,CONVERT(VARCHAR(50),'12/07/2015',101))
AND CustomerID NOT IN(SELECT c.CustomerID
FROM Customer c
INNER JOIN orderdetails od ON c.CustomerId = od.CustomerID
WHERE C.RegisteredDate
BETWEEN CONVERT(DATETIME,CONVERT(VARCHAR(50),'12/04/2015',101))
AND CONVERT(DATETIME,CONVERT(VARCHAR(50),'12/07/2015',101))
AND Transactionid IS NOT NULL
)

Related

What is causing the error "Column does not match the value count at row 1"?

SQL Code:
CREATE TABLE EMPLOYEE_ORDERS (
TOTAL_HANDLED INT,
CONSTRAINT PK_TOTAL PRIMARY KEY (TOTAL_HANDLED)
);
INSERT INTO EMPLOYEE_ORDERS (
SELECT COUNT(ORDERS.EMPLOYEE_ID), EMPLOYEE.EMPLOYEE_ID
FROM ORDERS LEFT JOIN EMPLOYEE
ON ORDERS.EMPLOYEE_ID = EMPLOYEE.EMPLOYEE_ID
GROUP BY EMPLOYEE.EMPLOYEE_ID
ORDER BY COUNT(ORDERS.EMPLOYEE_ID));
I've attempted: INSERT INTO EMPLOYEE_ORDERS (TOTAL_HANDLED) (SELECT....
I'm trying to return the ID of all employees who have handled more than 0 orders, any suggestions would be much appreciated
Your subquery is returning two values, but you only have one column in the table. You need to rewrite your subquery to get rid of the COUNT value and use it in a HAVING clause to filter the employee ids:
INSERT INTO EMPLOYEE_ORDERS
SELECT EMPLOYEE.EMPLOYEE_ID
FROM ORDERS
LEFT JOIN EMPLOYEE ON ORDERS.EMPLOYEE_ID = EMPLOYEE.EMPLOYEE_ID
GROUP BY EMPLOYEE.EMPLOYEE_ID
HAVING COUNT(ORDERS.EMPLOYEE_ID) > 0
Note there is no point having an ORDER BY in your subquery as it won't have any effect on the rows inserted into the table.
Note also that by replacing the LEFT JOIN with a JOIN and swapping the order of the tables you will automatically only get employees that have 1 or more matching orders, thus allowing you to simplify the query:
INSERT INTO EMPLOYEE_ORDERS
SELECT DISTINCT EMPLOYEE.EMPLOYEE_ID
FROM EMPLOYEES
JOIN ORDERS ON ORDERS.EMPLOYEE_ID = EMPLOYEE.EMPLOYEE_ID
If you are just looking for a employee-list comparison of the order table with a return of employees with an order count above 0, I'd probably do something like:
SELECT DISTINCT emp.Employee_ID
, COUNT(Order_ID)
FROM ORDERS ord
RIGHT OUTER JOIN EMPLOYEES emp ON emp.Employee_ID = ord.Employee_ID
GROUP BY emp.Employee_ID
HAVING COUNT(Order_ID) > 0
I'm trying to return the ID of all employees who have handled more than 0 orders
In other words, you just want employees who are in the ORDERS table. Probably the best method is:
SELECT DISTINCT o.EMPLOYEE_ID
FROM ORDERS o
If you want the count as well, use GROUP BY:
SELECT o.EMPLOYEE_ID, COUNT(*)
FROM ORDERS o
GROUP BY o.EMPLOYEE_ID;
No JOIN is necessary. The employees that you are looking for are already in ORDERS.

MySQL error code 1242

I'm trying to create a view of some columns from 3 different tables. One of the columns 'OrderNumber' is in 2 of the tables so I'm trying to do a UNION for them, but because I've made a subquery it returns an 1242 error and won't return more than 1 row. I just want to know how I can rewrite this query so that there are no subqueries, or is there someway to bypass it. Or perhaps I need to write multiple queries? Though I'd prefer to keep it to the one query, thanks.
CREATE VIEW CustOrderItems AS
SELECT CustFirstName,
CustLastName,
(SELECT OrderNumber
FROM Orders
UNION
SELECT OrderNumber
FROM Order_Details)
OrderDate,
ShipDate,
QuantityOrdered * QuotedPrice as ItemTotal
FROM Customers JOIN Orders JOIN Order_Details;
Substitute whatever your customer id
drop view if exists custorders;
create view custorders as
SELECT c.CustFirstName,
c.CustLastName,
o.OrderNumber order_ordernumber,
od.OrderNumber orderdetails_ordernumber,
o.OrderDate,
o.ShipDate,
od.QuantityOrdered * od.QuotedPrice as ItemTotal
FROM Customers c
JOIN Orders o on c.id = o.cust_id
JOIN Order_Details od on o.ordernumber = od.ordernumber
where c.id = ?
It's not clear what are your join criteria because the statement syntax is bad. But I assume you want to join on OrderNumber like SELECT ... FROM Customers INNER JOIN Orders ON Customers.OrderNumber = Orders.OrderNumber. In this case, if you want to use order numbers from two tables just repeat the query and make union of the two like:
SELECT ,,, FROM Customers INNER JOIN Order_Details ON Customers.OrderNumber = Order_Details.OrderNumber
UNION
SELECT FROM Customers INNER JOIN Orders ON Customers.OrderNumber = Orders.OrderNumber

SQL - How do I list rows from one table on the basis of them not appearing in another?

I have a customers table (which contains customer ID and family name) and an orders table, and have to list the ID and names of customers that didn't place an order i.e do not appear in the orders table. I tried this:
SELECT custID,familyname
FROM customers
WHERE custID =
(SELECT custID
FROM orders
WHERE COUNT(custID)<1);
but am getting an error. Do I have to use NOT EXIST? Or NOT IN?
You don't have to use not exists. You should want to:
SELECT c.custID, c.familyname
FROM customers
WHERE not exists (select 1 from orders o where o.custId = c.custId);
You can also use an outer join and filter in on those instances where there is no match:
select c.custid, c.familyname
from customers c
left join orders o
on c.custid = o.custid
where o.custid is null

Error with SQL code

Trying to execute this code with COALESCE to group data together. When executing I see this error
Msg 207, Level 16, State 1, Line 11
Invalid column name 'OrderID'.
Msg 209, Level 16, State 1, Line 1
Ambiguous column name 'CustomerID'.
SELECT CustomerID,
FirstName,
LastName,
COALESCE(OrderIDCnt,0),
COALESCE(SKUCnt,0),
COALESCE(OrderTotal,0)
FROM Customer as c
left join (SELECT o.CustomerID,
SUM(OrderTotal) AS OrderTotal,
COUNT(OrderedProductSKU) AS SKUCnt,
COUNT(OrderID) AS OrderIDCnt
FROM Orders as o
inner join Orders_ShoppingCart as osc
on osc.OrderNumber=o.OrderNumber
and osc.CustomerID=o.CustomerID
GROUP BY o.CustomerID
)ord
ON ord.CustomerID = c.CustomerID
try to use c.CustomerId or ord.CustomerId
The error means that SQL parser cannot uniquely resolve the unqialified name CustomerID. There are two candidates there:
The CustomerID field of the Customer table, and
The CustomerID field of the ord sub-query.
Although the two must match, because your join condition requires that ord.CustomerID = c.CustomerID, the query parser cannot arbitrarily pick one for you. Therefore, you need to either disambiguate this manually by specifying c or ord in front of CustomerID, or pick a different name for CustomerID in the subquery.
The first approach:
SELECT c.CustomerID, -- Add c. in front of CustomerID
FirstName,
LastName,
COALESCE(OrderIDCnt,0),
COALESCE(SKUCnt,0),
COALESCE(OrderTotal,0)
FROM Customer as c
left join (SELECT o.CustomerID,
SUM(OrderTotal) AS OrderTotal,
COUNT(OrderedProductSKU) AS SKUCnt,
COUNT(o.OrderID) AS OrderIDCnt -- Disambiguated OrderID
FROM Orders as o
inner join Orders_ShoppingCart as osc
on osc.OrderNumber=o.OrderNumber
and osc.CustomerID=o.CustomerID
GROUP BY o.CustomerID
)ord
ON ord.CustomerID = c.CustomerID
The second approach:
SELECT CustomerID,
FirstName,
LastName,
COALESCE(OrderIDCnt,0),
COALESCE(SKUCnt,0),
COALESCE(OrderTotal,0)
FROM Customer as c
left join (SELECT o.CustomerID as OrderCustomerID, -- add an alias
SUM(OrderTotal) AS OrderTotal,
COUNT(OrderedProductSKU) AS SKUCnt,
COUNT(o.OrderID) AS OrderIDCnt -- Disambiguated OrderID
FROM Orders as o
inner join Orders_ShoppingCart as osc
on osc.OrderNumber=o.OrderNumber
and osc.CustomerID=o.CustomerID
GROUP BY o.CustomerID
)ord
ON ord.OrderCustomerID = c.CustomerID -- Rename the field
Edit : Disambiguated OrderID.
You have field named customerId in tables Orders and Customer and you don't specify which you want to include in select clause.
In this case you always should type the field in format alias.field

SQL max of a count involving 3 tables

I have one table Customers with CustomerID and PhoneNumber, the second table is Orders that has CustomerId and OrderNumber and a third table OrderDetails that has OrderNumber, PriceOfOneUnit and UnitsOrdered. I need to find the PhoneNumber for the customer who placed the largest order (PriceOfOneUnit * UnitsOrdered). Doing a count(PriceOfOneUnit*UnitsOrdered) as A1 and then `Group By CustomerId Order By A1 DESC LIMIT 1 is evidently not working after joining the 3 tables. Can anyone help.
If we take you at your word, and what you want is the biggest single line-item rather than the largest order, you can find the largest line-item and then find the order to which it belongs and then the customer who placed that order. You can use a dummy aggregate function to pull back the order id from orderDetails.
EDIT:
OK, for someone just starting out, I think it can be clearer to think in terms of Venn diagrams and use what are called Inline Views and subqueries:
select customername, phone
from customer
inner join
(
select o.id, customerid from orders o
inner join
(
select od.orderid from orderdetail od
where (od.qty * od.itemprice) =
(
select max(od.qty * od.itemprice)
from orderdetail as od
)
) as biggestorder
on o.id = biggestorder.orderid
) as X
on customer.id = X.customerid
Each of the queries inside parentheses returns a set that can be joined/intersected with other sets.
Give this a try,
SELECT cus.CustomerId, cus.PhoneNumber
FROM Customers cus
INNER JOIN Orders a
ON cus.CustomerId = a.CustomerId
INNER JOIN OrderDetails b
On a.OrderNumber = b.OrderNumber
GROUP BY cus.CustomerId, cus.PhoneNumber
HAVING SUM(b.PriceOfOneUnit * b.UnitsOrdered) =
(
SELECT SUM(b.PriceOfOneUnit * b.UnitsOrdered) totalOrdersAmount
FROM Orders aa
INNER JOIN OrderDetails bb
On aa.OrderNumber = bb.OrderNumber
GROUP BY aa.CustomerId
ORDER BY totalOrdersAmount DESC
LIMIT 1
)