Updating fields based on results of a query - sql

So in this scenario a person can order products. I have a query that returns the result of an order ID and give the products that person ordered.
My issue is adapting this to an update query so the quantity from the OrderProduct table/query is then subtracted from the amount of stock in the Product Table.
SQL to create the table supplied below and the query to get the results
CREATE DATABASE StockControl;
CREATE TABLE Membership (
MemberID int NOT Null,
LastName varchar(255),
FirstName varchar(255),
Primary Key(MemberID)
);
CREATE TABLE Orders (
OrderID int NOT Null,
MemberID int,
Primary Key(OrderID)
);
CREATE TABLE Product (
ProductID int NOT Null,
Price int,
Stock int,
Primary Key(ProductID)
);
CREATE TABLE OrderProduct (
ProductID int,
OrderID int,
Quantity int
);
INSERT INTO Membership(MemberID,LastName,FirstName)
VALUES (2,'Me','Too'),(33,'Darren','Kelly');
INSERT INTO Orders(OrderID,MemberID)
VALUES (1,33),(5,2);
INSERT INTO Product(ProductID,Price,Stock)
VALUES (1,30,12),(2,25,12),(3,25,12),(4,25,12),(5,25,12),(6,25,12),(7,25,12),(8,25,12),(9,25,12),(10,25,12);
INSERT INTO OrderProduct(ProductID,OrderID,Quantity)
VALUES (1,5,1),(3,1,4),(9,1,6),(10,1,2);
This is the query to return all products as part of orderID 1, in the full version this will be able to be variable.
SELECT OrderProduct.ProductID, OrderProduct.OrderID, OrderProduct.Quantity, Product.Price, [Quantity]*[Price] AS Cost
FROM Product INNER JOIN OrderProduct ON Product.ProductID = OrderProduct.ProductID
GROUP BY OrderProduct.ProductID, OrderProduct.OrderID, OrderProduct.Quantity, Product.Price, [Quantity]*[Price]
HAVING (((OrderProduct.OrderID)=1))
ORDER BY OrderProduct.OrderID;
This returns the correct result but when trying to implement this to an update I get stuck. I want it so it looks through the 3 results and will subtract 4 from product 3, 6 from product 9 and 2 from product 10
Attempt so far
UPDATE SingleOrder INNER JOIN Product ON SingleOrder.ProductID = Product.ProductID SET Product.Stock = Product.Stock-SingleOrder.Quantity WHERE ((Product.ProductID=SingleOrder.ProductID));
If this is not clear I am happy to update the question etc.
Thanks

Related

Group by count multiple tables

Need to find out why my group by count query is not working. I am using Microsoft SQL Server and there are 2 tables I am trying to join.
My query needs to bring up the number of transactions made for each type of vehicle. The output of the query needs to have a separate row for each type of vehicle such as ute, hatch, sedan, etc.
CREATE TABLE vehicle
(
vid INT PRIMARY KEY,
type VARCHAR(30) NOT NULL,
year SMALLINT NOT NULL,
price DECIMAL(10, 2) NOT NULL,
);
INSERT INTO vehicle
VALUES (1, 'Sedan', 2020, 240)
CREATE TABLE purchase
(
pid INT PRIMARY KEY,
vid INT REFERENCES vehicle(vid),
pdate DATE NOT NULL,
datepickup DATE NOT NULL,
datereturn DATE NOT NULL,
);
INSERT INTO purchase
VALUES (1, 1, '2020-07-12', '2020-08-21', '2020-08-23')
I have about 10 rows on information in each table I just haven't written it out.
This is what I wrote but it doesn't return the correct number of transactions for each type of car.
SELECT
vehicle.vid,
COUNT(purchase.pid) AS NumberOfTransactions
FROM
purchase
JOIN
vehicle ON vehicle.vid = purchase.pid
GROUP BY
vehicle.type;
Any help would be appreciated. Thanks.
Your GROUP BY and SELECT columns are inconsistent. You should write the query like this:
SELECT v.Type, COUNT(*) AS NumPurchases
FROM Purchase p JOIN
Vehicle v
ON v.vID = p.pID
GROUP BY v.Type;
Note the use of table aliases so the query is easier to write and read.
If this doesn't produce the expected values, you will need to provide sample data and desired results to make it clear what the data really looks like and what you expect.

Returning values using a query that have been awarded a bonus

I'm trying to transactionId that were randomly chosen to be awarded a bonus which is essentially just having their rewardValue be double.
Following is my schema:
CREATE TABLE rewards (
rewardId INTEGER PRIMARY KEY,
rewardType VARCHAR(20),
rewardValue NUMERIC(6,2)
);
CREATE TABLE deposit (
depositId INTEGER PRIMARY KEY,
depositDate DATE,
customerId INTEGER NOT NULL REFERENCES Customers
);
CREATE TABLE transactions (
transactionId SERIAL PRIMARY KEY,
depositId INTEGER NOT NULL UNIQUE REFERENCES Orders,
transactionAmount NUMERIC(18,2)
);
Here's my query:
select distinct t.transactionId
from transactions t join deposit d on t.depositId = d.depositId join
rewards r on 2 * r.rewardValue <= t.transactionAmount;
I get some output which is just a few values repeating over and over. Does anyone know how to fix this?
before answer your question, seems like your join have a issue.
if you want to find transactions eligible for rewards
try this ->
select distinct transactionId from
(select t.transactionId,r.rewardValue,t.transactionAmount
from transactions t join deposit d on t.depositId = d.depositId,rewards r ) tbl where 2*rewardValue <= transactionAmount

SQL Server 2008 R2: Show only recently added records

I have two tables:
Cust : Contains customer details like customer ID and customer Name.
Cust_Address : This table contains customer ID and customer address.
Table: Cust
create table cust
(
cust_id int,
cust_name varchar(10)
);
Records Insertion:
insert into cust values(1,'A');
insert into cust values(2,'B');
insert into cust values(3,'C');
insert into cust values(4,'D');
Table: Cust_Address
create table cust_address
(
cust_id int,
cust_add varchar(50)
);
Records Insertion:
insert into cust_address values(1,'US');
insert into cust_address values(2,'UK');
insert into cust_address values(3,'UAE');
insert into cust_address values(4,'SA');
insert into cust_address values(1,'AUS');
insert into cust_address values(2,'IND');
insert into cust_address values(3,'SL');
insert into cust_address values(1,'CHINA');
Now I want to show the result which contains the latest customer address which have been inserted in the table Cust_Address.
Expected Result:
Cust_ID Cust_Name Cust_Add
-------------------------------
1 A CHINA
2 B IND
3 C SL
4 D SA
Here is the SQLFiddle for tables and its records.
You are not able to retrieve the rows in any particular order. You need some more info to get an order.
The best way is primary index in Cust_address
CustAddrID int identity(1, 1) not null primary key
You can also have a CreatedOn column that will have default value equal to getDate()
After that you can figure out what is the last inserted value for CustAddr for each Cust record.
In case you are not able to add new column there then maybe
change tracking functionality. But your issue seems to be too trivial for that.
There are also Temporal Tables in SQL Server 2016. But again it's probably too much.
Here is an example how you can get the address using primary key CustAddrID
SQL Fiddle
select cust_name, cust_add
from cust C
join
(select
cust_add, cust_id,
row_number() over (partition by cust_id order by cust_add_id desc) rn
from cust_address ) CLA
on CLA.cust_id = C.cust_id and
CLA.rn = 1
Identity column increases every time when we insert new value to the table. The correct value for your case will be the record with the highest cust_add_id and specified cust_id.
In the above query we generates numbers in desc order starting from 1 using row_number() function for each cust_id (partition by cust_id). Finally we take only the records with generated number rn equal to 1 CLA.rn = 1 and we join it to cust table.
You can replace row_number() by max(cust_add_id) and group by cust_id. However in that case you need to join cust_add table twice.
You will not be able to get the rows out of the link table in the order they were inserted.
You need to have a column for this.
Imagine how big the meta-data would be if you needed to keep a record for each record for creation! Would you also want to keep meta-data on your meta-data so you know when the meta-data was updated? The space use can quickly escalate.
SQL Server keeps some stats but something this specific will need to come from a user-defined field.
So you either use a identity column in the CustAddr table [CustAddr int identity(1, 1) not null primary key] or add a column for createdDateAndTime DateTime Default GetDate().

Oracle SQL Out put two table at a query

CREATE TABLE Products (
ID int,
name VARCHAR(70),
price NUMBER(8,2),
primary key (ID, name)
);
drop table Instock;
/* Delete the tables if they already exist */
create table Instock (
ID int,
quantity int
);
I have two table in my database. i want to have two table showing a output as a table that look like this
ID Name Price Quantity
SELECT A.ID,A.NAME,A.PRICE,B.QUANTITY FROM Products A,Instock B WHERE A.ID=B.ID
You can try this to create the new table(this creates the table in addition to putting the data in there)
CREATE TABLE MY_TABLE as SELECT A.ID,A.NAME,A.PRICE,B.QUANTITY FROM Products A,Instock B WHERE A.ID=B.ID

rewards the products qualify for

products purchased
--------------------------
bana
bana
bana
stra
kiwi
reward requirements table (related to a rewards table)
reward id, products
----------------------
1,bana
1,bana
1,bana
2,stra
2,bana
3,stra
4,cart
5,bana
5,bana
5,oliv
Can you help me with sql to get rewards
the products purchased qualifies for?
In the case above the reward ids would be:
1
2
3
If there is a better design that would make the solution easier I welcome those as well. I'm using product names for the sake of easier explaining, I hope. (I'll replace with product ids later)
This query will solve your problem.
select r.reward_id
from (
select reward_id, product, count(*) needed
from reward_requirements
group by reward_id, product
) r
left join (
select product, count(*) bought
from products_purchased
group by product
) p on r.product=p.product and p.bought >= r.needed
group by r.reward_id
having count(reward_id) = count(distinct p.product)
order by r.reward_id
To make your design better, you could redo the reward_requirements to have the columns (product, needed) instead of having to list it multiple times. It will also get rid of the first subquery.
With this schema:
CREATE TABLE product
(
product_id int IDENTITY
, name varchar(50)
)
CREATE TABLE requirement
(
requirement_id int IDENTITY
, product_id int
, quantity int
, reward_id int
)
CREATE TABLE reward
(
reward_id int IDENTITY
, reward varchar(50)
)
CREATE TABLE purchased
(
purchased_id int IDENTITY
, product_id int
, quantity int
)
Your query becomes:
SELECT requirement.reward_id
FROM requirement
LEFT JOIN purchased
ON purchased.product_id = requirement.product_id
AND purchased.quantity >= requirement.quantity
GROUP BY requirement.reward_id
HAVING COUNT(purchased.product_id) = COUNT(requirement.reward_id);
Here's a SQLFiddle to play around with: http://sqlfiddle.com/#!3/e93c9/7