How to combine calculated fields with the same foreign key? - sql

The title might not be entirely accurate to my problem but I couldn't think of how to word it.
I'm using a view to calculate the adjusted unit price of an item after accounting for initial setup costs, so the calculated field looks something like this:
"SetupFee" + "Shipping" + ( "UnitPrice" * "Quantity" ) / "Quantity"
The table these fields are from is called ItemInvoice and has a foreign key to a table called just Item, which contains item-specific information such as the description. The problem I'm having is that this method will give me two different outputs when there are multiple invoices for an item. For instance, if I have one invoice for item 1 and two for item 2 it shows me:
ItemName - (Calculation)
Item1 - 45.11
Item2 - 60.30
Item2 - 50.67
I'm really rusty on my SQL and databases in general (and am using LibreOffice Base for the first time) and am wondering how I would combine the costs for both invoices and divide them both by the total quantity. So something like:
("SetupFee1" + "Shipping1" + ( "UnitPrice1" * "Quantity1" ) + "SetupFee2" + "Shipping2" + ( "UnitPrice2" * "Quantity2" )) / ("Quantity1" + "Quantity2")
...or just averaging the two separate results, though I'm not sure how that would change the decimal values.
So far I've made this view entirely in LibreOffice Base's Design View, but I'm not averse to using SQL if I know what I'm going to be doing.
EDIT: LibreOffice 7.0 and embedded HSQLDB datbase.

Okay so I think I've figured it out, though I feel like there should maybe be a simpler way of doing it.
Definitely had to delve into SQL statements on this one, but this seems to do what I want:
SELECT "Item Name", AVG("Adjusted Unit Price") AS "Average Adjusted Unit Price"
FROM (
SELECT "Item"."ItemName" AS "Item Name", ( "SetupFee" + "Shipping" + ( "UnitPrice" * "Quantity" ) ) / "Quantity" AS "Adjusted Unit Price"
FROM "ItemInvoice", "Item" WHERE "ItemInvoice"."ItemID" = "Item"."ItemID"
)
GROUP BY "Item Name"

Related

How do you make a query return a specific value every single time

Oracle SQL Developer Version 18.2.0.183, Build 183.1748 (READ ONLY ACCESS TO DB)
I am looking for a way to make a specific numerical value show up in the results of my query and then multiply that value by the result of another columns value. Here is what I got so far:
SELECT
DBSTAGE.AOWOD.TOQUANTITY "Quantity",
DBSTAGE.OAWOD.TOQUANTITY ?????? "Price",
DBSTAGE.OAWOD.TOQUANTITY * ?????? "Amount",
DBSTAGE.OAWOM.ID "ID Number"
FROM
DBSTAGE.OAWOD,
DBSTAGE.OAWOM
WHERE
DBSTAGE.AOWOM.WONUM = DBSTAGE.OAWOD.WONUM
AND DBSTAGE.AOWOM.STID = DBSTAGE.AOWOD.STID
This query output will will have 4 columns (Quantity, Price, Amount and ID Number). The "quantity" data format is NUMBER (5) and will always be a numerical value between 1 and 9. The "Price" data format is NUMBER (5) and will always be a numerical value and here is where I need help. I need it to always out put the price in the same numeric format of 200 on my query. You can probably guess what my next plea for help is. The "Amount" data format is NUMBER (5) and will always be a numerical value of the "Quantity" multiplied by the "Price".
DBSTAGE is the Schema
AOWOD & AOWOM are the tables
TOQUANTITY & ID are the columns on the table
Quantity, Price & Amount are the new columns in the query
Is this possible?
Thank you in advance for any help.
This is what the end results should look like
enter image description here
Some data and expected results would have been helpful in helping you. However, the answer to your question I believe is this. please note that you are using the quantity column 3 times which does seem odd to me. I think you mean to put the other column names here but i'm not certain. Also I made up a name for the price column you should replace with the correct name. Hard coding "200" in its place seems like a horrible idea to me.
SELECT dbstage.aowod.toquantity
"Quantity",
200
"Price",
round(dbstage.oawod.toquantity * 200, -1)
"Amount",
dbstage.oawom.id
"ID Number"
FROM dbstage.oawod,
dbstage.oawom
WHERE dbstage.aowom.wonum = dbstage.oawod.wonum
AND dbstage.aowom.stid = dbstage.aowod.stid

SQL - count amount of occurences for items in different price diapasons

I have a question about SQL, and I honestly tried to search methods before asking. I will give an abstract (but precise) description below, and will greatly appreciate your example of solution (SQL query).
What I have:
Table A with category ids of the items and prices (in USD) for each item. category id has int type of value, price is string and looks like "USD 200000000" (real value is multiplied by 10^7). Tables also has a kind column with int type of value.
Table B with relation of category id and name.
What I need:
Get a table with price diapasons (like 0-100 | 100-200 | ...) as column names and count amount of items for each category id (as lines names) in all of the price diapasons. All results must be filtered by kind parameter (from table A) with value 3.
Questions, that I encountered (and which caused to ask for an example of SQL query):
Cut "USD from price string value, divide it by 10^7 and convert to float.
Gather diapasons of price values (0-100 | 100-200 | ...), with given step in the given interval (max price is considered as unknown at the start). Example: step 100 on 0-500 interval, and step 200 for values >500.
Put diapasons of price values into column names of the result table.
For each diapason, count amount of items in each category (category_id). Left limit of diapason shall not be considered (e.g. on 1000-1200 diapason, items with price 1000 shall not be considered).
Using B table, display name instead of category id.
Response is appreciated, ignorance will be understood.
If you only need category ids, then you do not need B. What you are looking for is conditional aggregation, something like:
select category_id,
sum(case when cast(substring(price, 4, 100) as int)/10000000 < 100 then 1 else 0 end) as price_000_100
sum(case when cast(substring(price, 4, 100) as int)/10000000 >= 100 and cast(substring(price, 4, 100) as int)/10000000 < 200
then 1 else 0
end) as price_100_200,
. . .
from a
group by category_id
There is no standard way to do what you describe.
That is because to do (3) you need a pivot aka crosstab, and this is not in ANSI SQL. Each DBMS has it's own implementation. Plus dynamic columns in a pivot table are an additional complication.
For example, Postgres calls it a "crosstab" and requires the tablefunc module to be installed. See this SO question and the documentation. Compare to SQL Server, which uses the PIVOT command.
You can get close using reasonably standard SQL.
Here is an example based on SQLite. A little bit of conversion would provide a solution for other systems, e.g. SUBSTR would be substring(string [from int] [for int]) in postgre.
Assuming a data table of format:
and a category name table of:
then the following code will produce:
WITH dataCTE AS
(SELECT product_id AS 'ID', CAST(SUBSTR(price, 5) AS INT)/1000000 AS 'USD',
CASE WHEN (CAST(SUBSTR(price, 5) AS INT)/1000000) <= 500 THEN
100 ELSE 200
END AS 'Interval'
FROM data
WHERE kind = 3),
groupCTE AS
(SELECT dataCTE.ID AS 'ID', dataCTE.USD AS 'USD', dataCTE.Interval AS 'Interval',
CASE WHEN dataCTE.Interval = 100 THEN
CAST(dataCTE.USD AS INT)/100
ELSE
(CAST(dataCTE.USD-500 AS INT)/200)+5
END AS 'GroupID'
FROM dataCTE),
cleanCTE AS
(SELECT *, CASE WHEN groupCTE.Interval = 100 THEN
CAST(groupCTE.GroupID *100 AS VARCHAR)
|| '-' ||
CAST((groupCTE.GroupID *100)+99 AS VARCHAR)
ELSE
CAST(((groupCTE.GroupID-5)*200)+500 AS VARCHAR)
|| '-' ||
CAST(((groupCTE.GroupID-5)*200)+500+199 AS VARCHAR)
END AS 'diapason'
FROM groupCTE
INNER JOIN cat_name AS cn ON groupCTE.ID = cn.cat_id)
SELECT *
FROM cleanCTE;
If you modify the last SELECT to:
SELECT name, diapason, COUNT(diapason)
FROM cleanCTE
GROUP BY name, diapason;
then you get a grouped output:
This is as close as you will get without specifying the exact system; even then you will have a problem with dynamically creating the column names.

Create a "products you may be interested in" algorithm in SQL?

i have a problem which im not sure how to approach.
I have a simple database where i store products , users , and purchases of products by users.
Each product has a name , a category and a price.
My goal is the following :
I want to display a list of 5 items that are suggested as "You might be interested in" to the user.The main problem is that i don't just want to search LIKE %..% for the name , but i also want to take into account the types of products the user usually buys , the price range he usually buys at , and giving priority to products being bought more often.
Is such an algorithm realistic? I can think of some metrics , like grouping all categories into semantically "similar" buckets and calculating distance from that , but im not sure how i should rank them when there is multiple criteria.
Maybe i should give each criteria an importance factor and have the result be a multiplication of the distance * the factor?
What you could do is create 2 additional fields for each product in your database. In the first field called Type for example you could say "RC" and in the second field called similar you could say, "RC, Radio, Electronics, Remote, Model" Then in your query in SQL later on you can tell it to select products that match up between type and similar. This provides a system that doesn't just rely on the product name, as these can be deceiving. It would be still using the LIKE command, but it would be far more accurate as it's pre-defined by you as to what other products are similar to this one.
Depending on the size of your database already, I believe this to be the simplest option.
I was using this on MySql for some weighted search :
SELECT *,
IF(
`libelle` LIKE :startSearch, 30,
IF(`libelle` LIKE :fullSearch, 20, 0)
)
+ IF(
`description` LIKE :startSearch, 10,
IF(`description` LIKE :fullSearch, 5, 0)
)
+ IF(
`keyword` LIKE :fullSearch, 1, 0
)
AS `weight`
FROM `t`
WHERE (
-- at least 1 match
`libelle` LIKE :fullSearch
OR `description` LIKE :fullSearch
OR `keyword` LIKE :fullSearch
)
ORDER BY
`weight` DESC
/*
'fullSearch'=>'%'.str_replace(' ', '_', trim($search)).'%',
'startSearch'=>str_replace(' ', '_', trim($search)).'%',
*/

Further calculations from calculated fields in libreoffice base

Working on LibreOffice 4.4.5.2 / HSQLDB 1.8.0.10
Calculated fields are quite easy.. eg; "Field Name1" + "Field Name2" in a third field = a simple sum.
In my database I think I need further calculations from calculated fields within the same query.
These two sql statements are in the same query:
BuyPrice
S/H Paid
TaxPaid
"BuyPrice" + "S/H Paid" + "TaxPaid"
When the query runs, this outputs to a field with an alias of Total Cost
SellPrice
S/H Charged
"SellPrice" + "S/H Charged" - ( "SellPrice" * 0.132 + "S/H Charged" * 0.132 )
This outputs to a field with an alias of NET
This is exactly what I need, however I also need a third calculated field for Profit. I cant just enter "NET" - "Total Cost". If I create another query on top of the first one, I can reference the aliases and it works just fine but I can only get this into two separate "Table Controls"
Should this possibly be separate queries??
I simply don't know enough about any of this to get it to work.. any help or suggestions would be greatly appreciated
As you have found, you cannot use aliases within queries. You have to write out the entire calculation
"SellPrice" + "S/H Charged" - ( "SellPrice" * 0.132 + "S/H Charged" * 0.132 ) - ("BuyPrice" + "S/H Paid" + "TaxPaid")
to alias it to a column PROFIT. If you write two queries, when the program runs it internally writes out all the code like this. Two queries adds a bit of overhead calculation for the queries to be combined. The overhead may be worth it if it makes the queries more maintainable by you.

SQL: Calculate Percentage in new column using another column

I found it hard to describe what I wanted to do in the title, but I will be more specific here.
I have a reasonably long query:
SELECT
/*Amount earned with validation to remove outlying figures*/
Case When SUM(t2.[ActualSalesValue])>=0.01 OR SUM(t2.[ActualSalesValue])<0 Then SUM(t2.[ActualSalesValue]) ELSE 0 END AS 'Amount',
/*Profit earned (is already calculated then input into db, this just pulls that figure*/
SUM(t2.[Profit]) AS 'Profit',
/*Product Type - pulls the product type so that we can sort by product*/
t1.[ucIIProductType] AS 'Product Type',
/*Profit Percentage - This is to calculate the percentage of profit based on the sales price which uses 2 different columns - Case ensures that there are no wild values appearing in the reports as previously experienced*/
Case When SUM(t2.[ActualSalesValue])>=0.01 OR SUM(t2.[ActualSalesValue])<0 THEN (SUM(t2.[Profit])/SUM(t2.[ActualSalesValue])) ELSE 0 END AS 'Profit Percentage',
/*Percentage of Turnover*/
*SUM(t2.[ActualSalesValue])/(Select SUM(t2.[ActualSalesValue]) OVER() FROM [_bvSTTransactionsFull]) AS 'PoT'
/*The join is connect the product type with the profit and the amount*/
FROM [dbo].[StkItem] AS t1
INNER JOIN [dbo].[_bvSTTransactionsFull] AS t2
/*There attirbutes are the links between the tables*/
ON t1.[StockLink]=t2.[AccountLink]
WHERE t2.[TxDate] BETWEEN '1/Aug/2014' AND '31/Aug/2014' AND ISNUMERIC(t2.[Account]) = 1
Group By t1.[ucIIProductType]
The 'Percentage of Turnover' part I am having trouble with - I am trying to calculate the percentage of the Amount based on the total amount - using the same column. So eg: I want to take the Amount value in row 1, then divide it by the total amount of the entire column and then have that value listed in a new column. But I keep getting errors or I Keep getting 1 (because it wants to divide the value by the same value. CAN anyone please advise me on proper syntax for solving this:
/*Percentage of Turnover*/
*SUM(t2.[ActualSalesValue])/(Select SUM(t2.[ActualSalesValue]) OVER() FROM [_bvSTTransactionsFull]) AS 'PoT'
I think you want one of the following:
SUM(t2.[ActualSalesValue])/(Select SUM(t.[ActualSalesValue]) FROM [_bvSTTransactionsFull] t) AS PoT
or:
SUM(t2.[ActualSalesValue])/(SUM(SUM(t2.[ActualSalesValue])) OVER() ) AS PoT
Note: you should use single quotes only for string and date constants, not for column and table names. If you need to escape names, use square braces.