SQL View - Fetching Unit Price, Default Price & Customer Price - sql

I am hoping someone can help me with this SQL view.
I have a screen where you can add products to an order. This order is for a customer which may or may not have a special price for the item.
Essentially, I am after 3 figures:
The unit price for the product as input by the operator
The default price for the product (standard ratecard)
The special price for the client for this product (may not exist)
To simplify things, I have the following tables
OrderLine
OrderId
ProductId
ProductVariationId (can be null)
Ratecard
RatecardId
RatecardName
RatecardClient (Default master ratecard is ID 1)
RatecardClientId
RatecardId
ClientId
RatecardProduct
RatecardProductId
ProductId
ProductVariationId (can be null)
A product has an ID but can also have a product variation ID
I want to create a view for OrderLine which has the input price, the default ratecard price and the special price for that product.
I would like a view which gives me:
Product Id
UnitPrice From "OrderLine"
RatecardPrice From "RatecardProduct" relating to "Ratecard" with RatecardId = 1 (will always exist)
ClientRatecardPrice (Depends if there is an existing ratecard and entry in this ratecard for the client / product / variation )
I'm really hoping someone can get me started here as I'm really struggling!
Thank you in advance!

I have made some assumptions about where the price columns are, and also how the RateCardProduct joins to RateCard. It would be better if you included the actual table definitions with extra columns stripped out. But with the assumptions you can see in my table defs, this query should give you what you want.
create table ClientOrder(OrderID int, ClientID int)
create table OrderLine(OrderId int,ProductId int,ProductVariationId int, UnitPrice decimal(10,2))
create table Ratecard(RateCardId int,RatecardName varchar(50)) -- has default 1
create table RateCardClient(RatecardClientId int,RatecardId int,ClientId int)
create table RateCardProduct(RatecardProductId int, RateCardId int, ProductId int, ProductVariationId int, Price decimal(10,2))
select Clientorder.ClientID, ClientOrder.OrderID, OrderLine.ProductID, OrderLine.ProductVariationId,
OrderLine.UnitPrice as UnitPrice,
P1.Price as RateCardPrice,
P2.Price as ClientRateCardPrice
from ClientOrder
Join OrderLine on OrderLine.OrderID=ClientOrder.OrderID
-- Get the default price
join RateCardProduct P1 on P1.RateCardID=1
and P1.ProductId=OrderLine.ProductId
and isnull(P1.ProductVariationID,0)=isnull(OrderLine.ProductVariationID,0)
-- Get the customer specific price
left join RateCardClient on RateCardClient.ClientID=ClientOrder.ClientID
left join RateCardProduct P2 on P2.RateCardID=RateCardClient.RateCardID
and P2.ProductId=OrderLine.ProductId
and isnull(P2.ProductVariationID,0)=isnull(OrderLine.ProductVariationID,0)

Related

find all stores customers have made purchase

I have a table that contains all the transaction information
(transaction date, customer name, transaction amount, unit amount, store ID).
How to create a table which could properly show the stores that customer has visited? The customer could make purchase from multiple stores, so the relationship between customer and store should be one to many. I am trying to check the stores each customer had visited.
Example:
Transaction table
store_ID
transaction_date
customer_name
transaction_amount
transaction_unit
Expected Output
customer_name
store_list
This is just a Hypothesis problem. Maybe list all shopped store seprately could be better? (But I guess it might create chaos if we want to check customer who made purchase in those stores). Thanks in advance :)
Since you already have a table with all information needed, maybe you are asking for a view, to avoid denormalized/duplicated data.
Example is shown below. Here I will use sqlite syntax (text instead of varchar, etc). We are normalizing data to avoid problems - for example you have shown a table with customer names, but different customers can have the same name, so we use customer_id instead.
First the tables:
create table if not exists store (id integer primary key, name text, address text);
create table if not exists customer (id integer, name text, document integer);
create table if not exists unit (symbol text primary key);
insert into unit values ('USD'),('EUR'),('GBP'); -- static data
create table if not exists transact (id integer primary key, store_id integer references store(id), customer_id integer references customer(id), transaction_date date, amount integer, unit text references unit(symbol));
-- transaction is a reserved word, so transact was used instead
Now the view:
-- store names concatenated with ',' using sqlite's group_concat
create view if not exists stores_visited as select cust.name, group_concat(distinct store.name order by store.id) from transact trx join customer cust on trx.customer_id=cust.id join store on trx.store_id=store.id group by cust.name order by cust.id;
-- second version, regular select with multiple lines
-- create view if not exists stores_visited as select cust.id, cust.name, store.id, store.name from transact trx join customer cust on trx.customer_id=cust.id join store on trx.store_id=store.id;
Sample data:
insert into store values
(1,'store one','address one'),
(2,'store two','address two')
(3,'store three','address three');
insert into customer values
(1,'customer one','custdoc one'),
(2,'customer two','custdoc two'),
(3,'customer three','custdoc three');
insert into transact values
(1,1,1,date('2021-01-01'),1,'USD'),
(2,1,1,date('2021-01-02'),1,'USD'),
(3,1,2,date('2021-01-03'),1,'USD'),
(5,1,3,date('2021-01-04'),1,'USD'),
(6,2,1,date('2021-01-05'),1,'USD'),
(7,2,3,date('2021-01-06'),1,'USD'),
(8,3,2,date('2021-01-07'),1,'USD');
Testing:
select * from stores_visited;
-- customer one|store one,store one,store two
-- customer three|store one,store two
-- customer two|store one

Design a table in a RDB to sales of multiple items, and calculate the value of the sale

I'm designing a DB for a Mock app and I'm having issues conceptualizing the design of the "Sales" Table.
Supposing I have a
CASHIER table with ID as its PK, name and lname
ARTICLE table with ARTICLE_ID as PK, description, price, stock
SALES table with SALE_ID(pk), ARTICLE_ID(FK article), CASHIER_ID(fk for cashier ID), TOTAL_PRICE_OF_SALE , PRICE_OF_UNIT(FK to ARTICLE price) and UNITS_SOLD
how can I design SALES in such a way that several articles can be sold in 1 transaction?
Normalization rules speak against having a column hold several values, so I don't see how I could store all of the article_id that were sold in a transaction inside an array. Calculating the price also seems problematic.
I know that in DML, you can display a PK several times, but as far as I know, in DDL you can't insert a row with a repeated PK, so I don't see how I could achieve something like
SALE_ID | ARTICLE_ID | CASHIER_ID | TOTAL_PRICE_OF_SALE | PRICE_OF_UNIT | UNITS_SOLD
1 1ASB JOHNDOE1 50.00 25.00 1
1 351A JOHNDOE1 50.00 10.00 1
1 JS57 JOHNDOE1 50.00 15.00 1
In DDL.
Notice that TOTAL_PRICE_OF_SALE should also calculate its value on it's own, during insertion time, but I also don't know how to handle the multiplication of price_of_unit * units_sold and then sum all of it into total_price_of_sale.
You need a SALE_ITEM table to link an ARTICLE to a SALE.
CREATE TABLE SALE_ITEM (
SALE_ITEM_ID INT NOT NULL IDENTITY(1,1),
SALE_ID INT NOT NULL REFERENCES SALE(SALE_ID),
ARTICLE_ID INT NOT NULL REFERENCES ARTICLE(ARTICLE_ID),
QUANTITY INT,
-- Its usually safer to copy the price into the 'item' table
-- so that your order history is accurate even when
-- the price of the article increases
PRICE DECIMAL(9,2)
)
And remove ARTICLE_ID from SALE. Or you might prefer to call it SALE_ARTICLE
BTW when naming tables I recommend choosing to either use plural or singular table names... but don't use a mix as that will be confusing. Hence I have used SALE in this example.
Further I wouldn't use all capitals in table names, instead I would use Pascal Case e.g. SaleItem
Also don't store the total sale price unless you have a concrete requirement to do so. Its much simpler to query that when you need it - otherwise you typically need to add a trigger on SALE_ITEM. An example of the query method:
SELECT SUM(SI.Price*SI.Quantity) TotalPrice
FROM SALE S
INNER JOIN SALE_ITEM SI on SI.SALE_ID = S.SALE_ID;
Note: SALE_ITEM doesn't technically need a SALE_ITEM_ID column as you could use a composite key of SALE_ID,ARTICLE_ID but I prefer to always have a table specific PK.

Insert id retrieving data from different tables in SQL

I have a Table A with customers and a Table P with products.
I also have a table C which represents the purchased product by customers.
The table fields are as follow:
A (Customers)
user_id
Name
Surname
P (Products)
product_id
price
product name
C (Purchased products)
id
product_id
user_id
quantity
date
C is the many-to-many link between A and P.
Assume that today a customer named "Bob Wright" has bought a product called "Beautiful_magazine". Assume that both customer and product are already in the database.
How do I make the entry in the C table?
I know that I should use the insert into select statement but I am facing hard time because I should retrieve the user id form A and the product id form P and then placing them into a new line in C along with the function NOW() and a numerical values representing the price.
I cannot do that because I am a newbie.
Any hint?
EDIT
I would like to make it manually, using the INSERT statement without relying on the software.
Assume:
user_id: 890
Name: Bob
Surname: Wright
product_id: 4897
price: 5.90
product_name: Beautiful_magazine
I need to create a new line in C table as follow:
id (autoincremental)
product_id: 4897
user_id: 890
quantity: 1
date: '2017-2-20'
Obviously, the product_id and user_id from P and A should be retrieve through a select statement using the where statement.
If you are passing the data in from an application, use a procedure (assuming that the id auto increments)
CREATE PROCEDURE `AddSale` (IN ProdID INT, IN UserID INT, IN Qty INT)
BEGIN
insert into TableC (Product_ID, User_ID, Quantity, Date)
values (ProdID, UserID, Qty, Now());
END
In your application, call the procedure and passin the parameters

SQL counting the values from two columns and showing the result in other column at the same table

I have two columns in one table, looking like this:
CREATE TABLE Invoices
(
ID_Invoice...
....
UnitPrice decimal (15,2) NOT NULL,
Discount (15,2) NOT NULL,
)
So I want to add a new column in this table which count the final price - UnitPrice-Discount=TotalCost? Please help.
If you're using SQL Server, try a calculated column:
CREATE TABLE Invoices
(
ID_Invoice...
....
UnitPrice decimal (15,2) NOT NULL,
Discount (15,2) NOT NULL,
TotalCost AS UnitPrice - Discount
)
If you're using MySQL, your only option is to add a physical column. Don't do that - it denormalizes the table and doesn't bring any benefit. Just query the value on the fly:
SELECT
ID_Invoice,
UnitPrice,
Discount,
UnitPrice - Discount AS TotalCost
The MySQL query is simple enough, and by not storing the additional column you don't have to worry about the TotalCost, Discount, and UnitPrice columns getting out of sync.
Alter Table Invoices
Add TotalCost Decimal(15,2)
Will add the column to your table
Now to add values to new column do
Update Invoices
set TotalCost = UnitPrice - Discount
Please let me know if it works

SQL Query relationship coding

Need some help making this work please. Some help please to ensure I always return just one row per ProductID. My Product Table contains base information on Products which can be properties in this case. It links to the Properties table via a ProductCode.
What I would like is to have the query return just the one row which it really should. Essentially, the row should display the PropertyLabel whether or not there are values in the PropertyProductValues table for that particular propertyLabel. The code below returns a bunch of rows which really it shouldn't, or I don't want it to. And I would appreciate help fine tuning this please. thanks in Advance.
Create Table Product
{
ProductID uniqueidentifier,
ProductName Varchar(50),
ProductCode Varchar(50)
}
Create Table Properties
{
PropertyID uniqueidentifier,
PropertyProductcode Varchar(50)
}
Create Table PropertyProductValues
{
ID uniqueidentifier,
PropertyID uniqueidentifier,
ProductID uniqueidentifier,
PropertyLabel Varchar(50),
UnitID uniqueidentifier
}
Create Table unit
{
UnitID uniqueidentifier,
Unit Varchar(50)
}
Select productid , PropertyLabel
PropertyValue
PropertyUnit
from Product
inner join Properties on ProductCode = PropertyProductCode
left join PropertyProductValues on Properties.PropertyID = ProductProductValues.PropertyID
left join Unit on PropertyValues.UnitID = Unit.UnitID
Where ltrim(rtrim(lower(PropertyLabel))) = lower('Special')
Sample Data
Product Table
b0359c76-8622-4006-82f2-1b4c91a8f6b3 Brown Building YSHJT
aba475c4-5a5c-483a-9faa-67f67ff9672d Sket Building GTJHD54
8f645348-8871-4fad-8c85-9fc6a1169b33 HOUSE 9 DGFS345
Properties Table
27c6485b-f7a5-4243-9304-71939230964d DGFS345
88e911e5-bf40-4f14-89cc-4ed2984c342e GTJHD54
d217cc14-6fcb-4251-a6d7-8fd1b3398a32 YSHJT
689cfd9d-bc87-4e23-afb3-d6cbf1e961f6 FFFSRW
bf7ae151-2e3f-4e0a-bf8b-d44ef30cf276 WYSJD
PropertyProductValues Table
6cf47434-c834-455d-a606-3d10cb9f7ab3 b0359c76-8622-4006-82f2-1b4c91a8f6b3 b0359c76-8622-4006-82f2-1b4c91a8f6b3 Storey
82ee0f80-afe4-45c2-877c-e79ce286170f 27c6485b-f7a5-4243-9304-71939230964d b0359c76-8622-4006-82f2-1b4c91a8f6b3 Bedrooms
5ff7f809-6b1f-4d6c-a125-29ce67f097d7 27c6485b-f7a5-4243-9304-71939230964d 8f645348-8871-4fad-8c85-9fc6a1169b33 Bathrooms
7f634b81-1212-4223-af42-29b4dc2bafcc 27c6485b-f7a5-4243-9304-71939230964d aba475c4-5a5c-483a-9faa-67f67ff9672d Material
cae10884-edf0-4340-bde6-5207e28a07cc 689cfd9d-bc87-4e23-afb3-d6cbf1e961f6 b0359c76-8622-4006-82f2-1b4c91a8f6b3 Basement
83943759-39d7-406e-92ea-4202a9b1d716 bf7ae151-2e3f-4e0a-bf8b-d44ef30cf276 b0359c76-8622-4006-82f2-1b4c91a8f6b3 Storey
c045d0ff-34db-4427-9fb7-fd41fc92f310 bf7ae151-2e3f-4e0a-bf8b-d44ef30cf276 aba475c4-5a5c-483a-9faa-67f67ff9672d balcony
Unit Table
UNITID UNIT
3a4a5216-0704-495e-b0a7-560787e0847a kg
6b4493f6-c2e4-4682-b71d-93cb1893eb73 m
2f2b4fee-9e69-4a71-a098-36e2da71471e l
55c8e5bf-edde-4977-ab7b-8827e337a31e oz
19528647-bd9f-48e0-ba86-b722d5b8ab0e cm
cee5cd46-1ae4-4b49-8b1c-9b3e0bd5270f mm
It would help if you gave the table structure of your 3 tables, but in principle, to get 1 row per PropertyId, you'll be doing a GROUP BY PropertyId.