Calculated field in a header table that sums values from a different table - sql

I'm building a simple project database that holds data about foods and recipes. Recipes exist in the recipe header table that stores one row per recipe with basic overview and the recipe detail table stores rows for all ingredients that make up a recipe. What I want to achieve is a calculated column that shows the total number of calories per recipe.
I can get the total number of calories using the following query:
SELECT SUM(calories) FROM products pd
INNER JOIN recipe_detail rd ON pd.id = rd.product_id
WHERE rd.recipe_id = 1
This will get me the total calories for the first recipe. The problem is, I store the nutritional data in the products table for a specific number of grams (Usually 100g) whereas the recipe might need only 50g of a product. How do I adjust this query so that I would get a fraction of the calories I need?
I basically need to take the gram value of a product that belongs in a recipe, divide it by the gram value in the products table to get the ratio and then multiply that by the number of calories to get the answer.

Not sure about the names and types of your columns or how your information is stored exactly, but I think this might help:
SELECT r.*, SUM((p.calories * rd.weight) / p.weight::numeric) AS calories -- depending on the types of your columns, you can omit the cast; I added it to be sure it is not integer division
FROM recipe r
INNER JOIN recipe_detail rd ON rd.recipe_id = r.id
INNER JOIN porducts p ON p.id = rd.product_id
GROUP BY r.id

Related

SQL: Calculate the rating based on different columns and use it as an argument

I'm trying to calculate the rating based on a table that has 3 columns with different ratings ranging from 1 to 5.
I wanted to calculate the average of these 3 values and then be able to use this as an argument in queries, for example:
Where Rating >3.5
At this moment I have this that gives me the average for all suppliers
SELECT c.Name
,(SELECT CAST(AVG(rat) AS DECIMAL(5, 2))
FROM(
VALUES(b.Qty_Price),
(b.Quality),
(b.DeliveryTime)) A (rat)) AS Rating
FROM Order a
JOIN Evaluation b ON b.ID_Evaluation = a.ID_Evaluation
JOIN Supplier c ON c.NIF_Supplier = a.NIF_Supplier
What I would like now is, for example, to filter the providers that have more than 3 ratings, but I don't know how I can do that. If anyone can help i would be grateful
If the query works like you want it, you get the average for all entries, that is.
The WHERE rating > 3.5 cannot be added, as rating does not exist in the context of the SELECT-clause, nor the tables we JOIN.
To overcome this issue, we can keep the query that you have made, call it something different using WITH and SELECT from that sub-query WHERE rating > 3.5
It should look something like this:
WITH Averages(name, rating) AS
(SELECT c.name
,(SELECT CAST(AVG(rat) AS DECIMAL(5, 2))
FROM(
VALUES(b.qty_Price),
(b.quality),
(b.deliveryTime)) AS (rat)) AS rating
FROM Order a
JOIN Evaluation b ON b.ID_Evaluation = a.ID_Evaluation
JOIN Supplier c ON c.NIF_Supplier = a.NIF_Supplier)
SELECT name, rating FROM Averages WHERE rating > 3.5;
Now, we simply call the query you provided as Averages for example, and we SELECT from that table WHERE rating > 3.5.
Also note that you can have multiple WITHs to make things easier for you, but remember that a comma (,) is needed to seperate them. In our case, we only have 1 use of WITH ... AS, so no need for a comma or semi-colon after ...= a.NIF_Supplier)
Looks like you typed only "A" before "(rat)", it should be "AS". Also, remember that attributes should be lowercase, it makes it easier for all of us to distinguish tables from attributes.
Cheers!

How to make a query that return data of rows related to each row in table

i have some tables about Double-entry bookkeeping.
table VoucherDetail Contains Accounting Entries for Each Voucher and
other tables are Accounts Group/Ledger/Definitive
here are diagrams of tables
im trying to get opposite side of an entry and show it in a custom column that matches entry debit/credit amount(Ref to image 2).
i did some google search and find nothing. here is the query i made so far(Ref to image 1):
SELECT
dbo.Vouchers.VoucherId,
vd.VoucherDetailIndex AS ind,
vd.Debit,
vd.Credit,
vd.Description,
CONCAT ( ag.Name, '_', al.Name, '_', ad.Name ) AS names,
CONCAT ( ag.GroupId, '_', al.LedgerId, '_', ad.DefinitiveId ) AS ids
FROM dbo.Vouchers
JOIN dbo.VoucherDetails AS vd ON vd.Voucher_VoucherIndex = dbo.Vouchers.VoucherIndex
JOIN dbo.AccDefinitives AS ad ON vd.AccDefinitive_DefinitiveIndex = ad.DefinitiveIndex
JOIN dbo.AccLedgers AS al ON ad.AccLedger_LedgerIndex = al.LedgerIndex
JOIN dbo.AccGroups AS ag ON al.AccGroup_GroupIndex = ag.GroupIndex
here is the result im getting :
result i want to be :
here is an example to explain what i need :
EVENT :
we put 10$ on bank as our Equity, now we need to create a voucher for this:
INSERT INTO Vouchers(VoucherIndex, VoucherId, VoucherDate, Description) VALUES
(1, 1, 2019/01/01, initial investment);
and now we need to add Entry of this event to VoucherDetail of Voucher 1
which will have 2 entry; 1 for cash and 1 for Equity :
INSERT INTO VoucherDetails(VoucherDetailIndex, Debit, Credit, Description AccDefinitive_DefinitiveIndex, AccLedger_LedgerIndex, Voucher_VoucherIndex, EntityOrder) VALUES
(1, 10$, 0, 'Put Cash on Bank as initial Investment', 10101, 101, 1, 1),
(2, 0, 10$, 'initial Investment', 50101, 501, 1, 2);
now we run the first query i provided here is the result
now we have our common result, lets get to the problem
imagine someone filled these tables with 10000 row data
and we need to find Voucher no.10, with 20 entries inside VoucherDetail
we get these entries by doing a simple query.
but we don't know which related to which(like in above example Cash with 10$ debt related to Equity with 10$ credit)
if we want to know it, we need to spend time on it every time we need to find something
the query need to search whole table and find opposite side related to each row based on Debit or Credit value of row
this should be the result i wrote in excel :
as you can see in the image above there is 2 new columns added
Account in opposite Side and Account ID in opposite side
first row refers to Equity which related to Cash and
second row refers to Cash Which related to Equity.
As far as I can see, what you need to be able to do is join two VoucherDetail records that have the same Voucher_VoucherIndex value (let's call this VoucherID for brevity). However, the only two things these records have in common is their VoucherID and the fact that the Debit value = the Credit value in the other, and vice versa.
In the comments you mentioned that multiple VoucherDetail rows with the same VoucherID can have the same Debit value (and I presume Credit value). If this wasn't the case, you could add something like this to your query:
JOIN dbo.VoucherDetails AS vd_opposite
ON vd.Voucher_VoucherIndex = vd_opposite.Voucher_VoucherIndex
AND (vd.Debit = vd_opposite.Credit OR vd.Credit = vd_opposite.Debit)
You can't do this though, because Debit/Credit and VoucherID together are not enough to be unique, so you might pick up extra rows in the join that you don't want.
Therefore, your only option is to add a new ID field to your table (maybe called SaleID or something) that definitively links the two rows that represent opposite sides of the same "sale" with a common ID. Then, the above JOIN would look like this:
JOIN dbo.VoucherDetails AS vd_opposite
ON vd.Voucher_VoucherIndex = vd_opposite.Voucher_VoucherIndex
AND vd.SaleID = vd_opposite.SaleID
In addition to adding that JOIN, you would need to join the new vd_opposite table against all of the dbo.Acc* tables again to get access to the data you want, and obviously add the fields from those tables that you want in the results to your SELECT fields.

Summing up the price of production and selling prices

I need to write query and calculate the total CostPrice’s and total Sellprice’s related to Material of ID=1. I want to calculate total costs so I have to include the QuantityColumn from the table Materials right?
SELECT SUM((CostPrice) * M.Quantity) AS 'TotalCostExclusive', SUM((SellPrice) * M.Quantity) AS 'SellPriceExclusive'
FROM Materials AS M INNER JOIN Warehouse AS W
ON M.Warehouse_id = W.Id
WHERE M.Material_Id = '1';
I tried this, but I'm not sure the result is equal to the required task.
Now I want to write new query to include the Discount on both cost and selling prices.
Since I’m a beginner and this data model is for student purpose, I would like to know why I must to have a table WarehouseIdentities. What exactly this table doing here and what role it has.

Create one query with sum and count with each value pulled from a different table

I am trying to create a query that pulls two different aggregated values from three different tables during a specific date range. I am working in Access 2003.
I have:
tblPO which has the high level purchase order description (company name, shop order #, date of order, etc)
tblPODescription which has the dollar values of the individual line items from customers the purchase order
tblCostSheets which as a breakdown of the individual pieces that we need to manufacture to satisfy the customers purchase order.
I am looking to create a query that will allow me, based on the Shop Order #, to get both the sum of the dollar values from tblPODescriptions and the count of the different type of pieces we need to make from tblCostSheets.
A quick caveat: the purchase order may have 5 line items for a sum of say $1560 but it might take us making 8 or 9 different parts to satisfy those 5 line items. I can easily create a query that pulls either the sum or the count by themselves, but when I created my query with both, I end up with numbers that are multipled versions of what I want. I believe it is multiplying my piece counts and dollar values.
SELECT DISTINCTROW tblPO.CompanyName, tblPO.ShopOrderNo, tbl.OrderDate, Sum(tblPODescriptions.ItemAmount) AS SumOfItemAmount, Count(tblCostSheets.Description) AS CountOfDescription
FROM (tblPO INNER JOIN tblPODescriptions ON (tblPO.CompanyName = tblPODescriptions.CompanyName) AND (tblPO.PurchaseOrderNo = tblPODescriptions.PurchaseOrderNo) AND (tblPO.PODate = tblPODescriptions.PODate)) INNER JOIN tblCostSheets ON tblPO.ShopOrderNo = tblCostSheets.ShopOrderNo
GROUP BY tblPO.CompanyName, tblPO.ShopOrderNo, tblPO.OrderDate
HAVING (((tblPO.OrderDate) Between [Enter Start Date:] And [Enter End Date:]));

sql SUM value incorrect when using joins and group by

Im writing a query that sums order values broken down by product groups - problem is that when I add joins the aggregated SUM gets greatly inflated - I assume its because its adding in duplicate rows. Im kinda new to SQL, but I think its because I need to construct the query with sub selects or nested joins?
All data returns as expected, and my joins pull out the needed data, but the SUM(inv.item_total) AS Value returned is much higher that it should be - SQL below
SELECT so.Company_id, SUM(inv.item_total) AS Value, co.company_name,
agents.short_desc, stock_type.short_desc AS Type
FROM SORDER as so
JOIN company AS co ON co.company_id = so.company_id
JOIN invoice AS inv ON inv.Sorder_id = so.Sorder_id
JOIN sorder_item AS soitem ON soitem.sorder_id = so.Sorder_id
JOIN STOCK AS stock ON stock.stock_id = soitem.stock_id
JOIN stock_type AS stock_type ON stock_type.stype_id = stock.stype_id
JOIN AGENTS AS AGENTS ON agents.agent_id = co.agent_id
WHERE
co.last_ordered >'01-JAN-2012' and so.Sotype_id='1'
GROUP BY so.Company_id,co.company_name,agents.short_desc, stock_type.short_desc
Any guidence on how I should structure this query to pull out an "un-duplicated" SUM(inv.item_total) AS Value much appreciated.
To get an accurate sum, you want only the joins that are needed. So, this version should work:
SELECT so.Company_id, SUM(inv.item_total) AS Value, co.company_name
FROM SORDER so JOIN
company co
ON co.company_id = so.company_id JOIN
invoice inv
ON inv.Sorder_id = so.Sorder_id
group by so.Company_id, co.company_name
You can then add in one join at a time to see where the multiplication is taking place. I'm guessing it has to do with the agents.
It sounds like the joins are not accurate.
First suspect join
For example, would an agent be per company, or per invoice?
If it is per order, then should the join be something along the lines of
JOIN AGENTS AS AGENTS ON agents.agent_id = inv.agent_id
Second suspect join
Can one order have many items, and many invoices at the same time? That can cause problems as well. Say an order has 3 items and 3 invoices were sent out. According to your joins, the same item will show up 3 times means a total of 9 line items where there should be only 3. You may need to eliminate the invoices table
Possible way to solve this on your own:
I would remove all the grouping and sums, and see if you can filter by one invoice produce an unique set of rows for all the data.
Start with an invoice that has just one item and inspect your result set for accuracy. If that works, then add another invoice that has multiple and check the rows to see if you get your perfect dataset back. If not, then the columns that have repeating values (Company Name, Item Name, Agent Name, etc) are usually a good starting point for checking up on why the duplicates are showing up.