Add Column to Query From Same Table, Update Values in Duplicated Column? - sql

I'm trying to figure this one out. In this scenario, gas prices from a particular city in this database are increasing, so they will need to raise their prices 20%. I'm supposed to create a query that will display what the new price will be from that city only. Here is what it is supposed to look like:
Here is my code:
Select ProductID, tblProduct.ProductType, Price, SUM((Price *.20)+Price) AS 'Increased Price'
From tblProduct join tblCompany
On tblProduct.CompanyID = tblCompany.CompanyID
Where tblCompany.CompanyID IN
(Select CompanyID
From tblCompany
Where City = 'Kalamazoo')
Order By ProductID
However, when I go to execute the code, I get the following error:
Msg 8120, Level 16, State 1, Line 1
Column 'tblProduct.ProductID' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
I can't figure out what I'm doing wrong. Can anyone enlighten me?

You dont really need the SUM function if you are only calculating the 20% price increase...Do this instead
Select ProductID, tblProduct.ProductType, Price, ((Price *.20)+Price) AS 'Increased Price'
From tblProduct join tblCompany
On tblProduct.CompanyID = tblCompany.CompanyID
Where tblCompany.CompanyID IN
(Select CompanyID
From tblCompany
Where City = 'Kalamazoo')
Order By ProductID

Select tblProduct.ProductID, tblProduct.ProductType, tblProduct.Price, SUM((tblProduct.Price *.20)+tblProduct.Price) AS 'Increased Price'
From tblProduct join tblCompany
On tblProduct.CompanyID = tblCompany.CompanyID
Where tblCompany.CompanyID IN
(Select c.CompanyID
From tblCompany c
Where c.City = 'Kalamazoo')
Order By ProductID

The SUM() suggests an aggregation query. You have no GROUP BY, so the initial columns (ProductId, etc.) are not valid.
It is a good idea to use table aliases for queries. These make queries easier to write and to read. So:
Select p.ProductID, p.ProductType, p.Price, ((p.Price * 1.20) AS IncreasedPrice
From tblProduct p join
tblCompany c
On p.CompanyID = c.CompanyID
Where c.City = 'Kalamazoo'
Order By p.ProductID;
In addition, the IN clause is unnecessary. You can just check the city using the JOIN.

Related

Get all records having count from one table is greater than sum of other table

I have three tables 1) CustomerOrders, 2) StockItems and 3) OrderContentsLine. StockItems have customerorderid (one to many relationship with CustomerOrders) and OrderContentsLine contains order items with item quantity (obviously one to many relationship with CustomerOrders).
Now I want to get All orders which have sum of quantity from OrderContentsLine table greater than count of StockItems
myquery looks like this
select co.OrderNumber,si.SalesOrderID, sum(ocl.Quantity) Ordered, count(si.SalesOrderID) Allocated from CustomerOrders co
inner join StockItems si on co.OrderID = si.SalesOrderID
inner join OrderContentsLine ocl on ocl.OrderID=co.OrderID
where co.CompanyId=531
group by si.SalesOrderID,co.OrderNumber
having count(si.SalesOrderID)>sum(ocl.Quantity)
but this query shows no results, and I am damn sure that many orders have greater order conterntline items than sum of quantity from StockItems table.
Can you please review my query and suggest the better way to get these orders!
My required output is
NOTE: this output is not generated by query !
I have just created a query that gives me the required output
select * from(
select co.OrderNumber, co.OrderID, co.OrderStatus,
(select sum(tbl.Quantity) from OrderContentsLine tbl where tbl.OrderID=co.OrderID) Ordered,
(select count(*) from StockItems tbl2 where tbl2.SalesOrderID=co.OrderID ) Allocated
from CustomerOrders co
)temp where temp.Allocated> temp.Ordered
Your problem is the multiple one-to-many joins. You are counting and summing duplicates. For example, if you have 1 order with 2 stock items, and 3 order lines, your join of the three tables will have 6 rows. You have no relationship between StockItem and OrderContentsLine, so you get a cartesian product.
You probably want something like
WITH ord AS
(
SELECT co.CompanyId, co.OrderID, co.OrderNumber, SUM(ocl.Quantity) AS Ordered
FROM CustomerOrders co
INNER JOIN OrderContentsLine ocl ON ocl.OrderID = co.OrderID
GROUP BY co.CompanyId, co.OrderNumber
), al AS
(
SELECT co.CompanyId, co.OrderID, co.OrderNumber, COUNT(si.SalesOrderID) AS Allocated
FROM CustomerOrders co
INNER JOIN StockItems si ON co.OrderID = si.SalesOrderID
GROUP BY co.CompanyId, co.OrderNumber
)
SELECT ord.CompanyId, ord.OrderNumber, ord.Ordered, al.Allocated
FROM ord
INNER JOIN al ON ord.OrderID = al.OrderID
WHERE companyId = 531
AND al.Allocated > ord.Ordered
Obviously hard to test with no data

Define sort order when updating

I have a script that updates an ID field on one table where that record matches to another table based on criteria.
Below is the general structure of my query.
update p.saleId = e.saleId
from products p inner join sales s on s.crit1 = p.crit1
where p.someDate between s.startDate and s.endDate
This is working fine. My issue is that in some situations there is more than one match on the 'sales' table with this query which is generally ok. I'd however like to sort these results based on another field to make sure the saleId I get is the one with the highest cost.
Is that possible?
As it is the saleID you want to set and the sales table you are looking up, you can probably just update all products records. Then you can write a simple update statement on the table and don't have to join. This makes this much easier to write:
update products p
set saleId =
(
select top(1) s.saleId
from sales s
where s.crit1 = p.crit1
and p.someDate between s.startDate and s.endDate
order by cost desc
);
The main difference to your statement is that mine sets saleId = NULL where there is no match in the sales table, while your lets these untouched. But I guess that doesn't make a difference here.
I hope the below query may solve. Wrote very high level draft as per your question. Please take only the concept not the syntax.
with maxSales as (select salesId, crit1 from sales s1
where cost = (select max(cost) from
sales s2 where s1.crit1 = s2.crit1)
update products p set p.saleId =
(select s.saleId from
maxSales s
where s.crit1 = p.crit1
and p.someDate between s.startDate and s.endDate)
UPDATE p
set p.saleId = e.rowNumber
FROM products p
INNER JOIN
(SELECT saleId, row_number() OVER (ORDER BY saleId DESC) as rowNumber
FROM sales)
e ON e.saleId = p.saleId
TRY THIS:
UPDATE p
SET p.saleid = s.saleid
FROM products p
INNER JOIN
(SELECT s.crit1,
s.saleid
FROM sales s
WHERE cost IN
(SELECT max(cost) cost
FROM sales
GROUP BY crit1)) s ON s.crit1 = p.crit1
None of the answers worked, but I managed to do it by using and Outer Apply as my join, and specified the sort order in that.
Cheers everyone for the input.

Issue with IfNull using a join | Big Query

I need some help. I've got three tables that I need information from. The most important parameter is the DealID from my table Flostream.orders. If this is null, I want it replaced with the Mobileheads.survey.sales_rule which is the same format.
I've constructed this:
SELECT
filename,
IFNULL(dealID,mobileheads.surveys.sales_rule) AS DealIDcombo,
COUNT(*) AS Total,
SUM(integer(weight)) AS TotalWeight,
SUM(Productweight)/1000 AS SumWeight,
Currency,
Deliverybasecost,
ROUND(SUM(Deliverybasecost),2) AS TotalDelCost,
Productsku,
Productname,
Dealstartdate
FROM
[flostream.orders]
LEFT OUTER JOIN flostream.briisk
ON dealID = Uniquereference
LEFT OUTER JOIN mobileheads.surveys
ON mobileheads.surveys.order_number = ExternalReference
GROUP BY
filename,
DealIDCombo,
currency,
Deliverybasecost,
Productname,
Productsku,
dealstartdate
ORDER BY
filename,
Total desc;
My issue is with this:
LEFT outer JOIN flostream.briisk ON dealID = Uniquereference
Ideally I would like it to be:
LEFT outer JOIN flostream.briisk ON dealIDCombo = Uniquereference
but unfortunately that doesn't work.
Any ideas on how to tackle this?
This is because the join can't access fields that are computed after the join.
See how Ifnull uses the joined table. You need to nest these tables.
First the join with mobileheads.surveys and then the next join.
SELECT * FROM(
SELECT
filename,
IFNULL(dealID,mobileheads.surveys.sales_rule) AS DealIDcombo,
COUNT(*) AS Total,
SUM(integer(weight)) AS TotalWeight,
SUM(Productweight)/1000 AS SumWeight,
Currency,
Deliverybasecost,
ROUND(SUM(Deliverybasecost),2) AS TotalDelCost,
Productsku,
Productname,
Dealstartdate
FROM
[flostream.orders]
LEFT OUTER JOIN mobileheads.surveys
ON mobileheads.surveys.order_number = ExternalReference) as first
LEFT OUTER JOIN flostream.briisk
ON first.dealIDCombo = Uniquereference
GROUP BY
filename,
DealIDCombo,
currency,
Deliverybasecost,
Productname,
Productsku,
dealstartdate
ORDER BY
filename,
Total desc;
Excuse the mess, i don't know where these field belong to. Hopefully this helps. Ask me if you need more explanation!

passing a parameter into a subquery

i was wondering if it is possible to pass a parameter into a select subquery.
What i want to do is collect some product data from one table and then crossref the weight of the item to it's carriage cost in a shipping table to return a cost.
something like:
select cataloguenumber, productname,
(select shipping.carriagecost
from shipping
where shipping.carriageweight = weight) as carriagecost
from products
Regards
DPERROTT
While the subquery would work, a better, more readable and efficient way to define this would be as follows:
SELECT p.cataloguenumber
, p.productname,
, s.carriagecost
FROM products p
INNER JOIN
shipping s
ON p.weight = s.carriageweight
This assumes that all product weights have a corresponding entry in the shipping table. If that is not the case then change from INNER JOIN to LEFT JOIN and deal with any nulls.
select cataloguenumber, productname, shipping.carriagecost as carriagecost
from products, shipping
where shipping.carriageweight = products.weight
or am I missing something?
SELECT DISTINCT cataloguenumber, productname, shipping.carriagecost
FROM products
LEFT OUTER JOIN shipping
ON shipping.carriageweight = products.weight
Your subquery should only return 1 row, if it returns more then that your query will throw an error in run-time.
This is possible I think, but then you should retrieve the column you want to pass in your parent query.
select cataloguenumber, productname, weight
(select shipping.carriagecost
from shipping
where shipping.carriageweight = weight) as carriagecost
from products
SELECT DISTINCT products.cataloguenumber, products.productname, shipping.carriagecost
FROM products
LEFT JOIN shipping ON shipping.carriageweight = products.weight

Get Product Onhand Quantity

Using sqlite3, I have two tables: products, orders. I want to know how many products are left in the shop.
SELECT pid,
txt,
price,
qty-coalesce((SELECT SUM(qty)
FROM ORDERS
WHERE pid=?),0)
FROM PRODUCTS
WHERE pid=?
This works if I select 1 product, I would like a list of all my products ?
SELECT
P.pid, P.txt, P.price,
P.qty - coalesce((SELECT sum(O.qty) FROM orders O WHERE O.pid = P.pid), 0)
FROM products P
Try this:
SELECT
pid,
txt,
price,
qty-coalesce(
(SELECT sum(qty)
FROM orders
WHERE orders.pid = products.pid),0)
FROM products
I recommend using:
SELECT t.pid,
t.txt,
t.price,
t.qty - IFNULL(qs.qty_sold, 0) 'onhand_qty'
FROM PRODUCTS t
LEFT JOIN (SELECT o.pid,
SUM(o.qty) 'qty_sold'
FROM ORDERS o) qs ON qs."o.pid" = t.pid
WHERE t.pid = ?
While it works, using correllated SELECT statements in the SELECT clause will have the worst performance because they are executing once for every row returned in your query.
IFNULL is preferrable to use in this case compared to COALESCE. COALESCE is intended for checking 2+ values for being null, giving a false impression when someone else reads your code. There isn't any inherent benefit - per the documentation, they are the same.
Reference: SQLite Core Functions