How to use sqlite db functions to set values from calculation - sql

I have an app (its ruby on rails but it shouldn't matter) where I am bulk loading items and quantities per branch.
The database is sqlite.
Say I have a two tables: items and quantities.
items columns:
id
quantity
quantities columns:
id
item_id
branch_id
value
I need to be able to loop through all records in the items table set the item.quantity to the sum of all quantity.value where item_id matches item.id
I would like to know if there is a way to do this all within a sql query (the select and update) so that I don't have to pull the data out of the database, do the calculation and then write the updated quantity back to each item, instead I would like to have it all occur in the database using sql statements and functions.
Is this possible in a sql query function db side?
example:
item[1] = {id=>1,quantity=>0}
quantity[1] = {id=>1,item_id=>1,value=>100,branch_id=>1}
quantity[2] = {id=>2,item_id=>1,value=>200,branch_id=>2}
quantity[3] = {id=>3,item_id=>1,value=>300,branch_id=>3}
item[1].quantity = quantity[1].value + quantity[2].value + quantity[3].value

You can do this with an update query. In this case, you can use a correlated subquery to calculate the sum of the quantities for a given item:
update item
set quantity = (select sum(value) from quantities where item.id = quantities.item_id);
EDIT:
If you want to speed it up putting an index on quantities(item_id, value).
You could also summarize quantities in a temporary table and use this instead. The index, however, however, should be sufficient for performance.

You are duplicating your data! Which means you must always keeping everything in sync.
I would prefer to create a view and get total quantities from there:
CREATE TABLE items(id, ...);
CREATE TABLE quantities(id, item_id, branch_id, value, ...);
CREATE VIEW items_sum AS SELECT items.*, SUM(quantities.value) AS quantity FROM items LEFT JOIN quantities ON items.id=quantities.item_id GROUP BY items.id;
As items_sum is a query, you don't have to update it. SELECT * FROM items_sum;will return desired results for total quantities.

Related

sql can't check column1>column2 not working

I have some problem in sql syntax.
i have products table and below two column
total_quantity (Its total quantity for products)
remain_alert_quantity
i want to get records that are below remain_alert_quantity
select * from products where total_quantity<remain_alert_quantity
but its not work .
can i check condition with column value in sql.
thanks and regards.
Given data is not sufficient so I am assuming few thing like,
you want to compare the product quantity with the remain_alert_quantity of same product.
There is some unique column in table (like product_id)
in this case try the below query.
select * from products a where a.total_quantity<
(select b.remain_alert_quantity from products b where b.product_id=a.product_id);

How to join products and their characteristics

How to join products and their characteristics
I have two tables.
Product (id, title, price, created_at, updated_at etc)
and
ProductCharacteristic(id, product_id, sold_quantity, date, craated_at, updated_at etc).
I should show products table (header is product.id, product.title, product.price, sold_quantity) for some period of time and ordered by any fields from header.
And I can't write query
Now I have following query
> current_project.products.includes(:product_characteristics).group('products.id').pluck(:title, 'SUM(product_characteristics.sold_quantity) AS sold_quantity')
(45.4ms) SELECT "products"."title", SUM(product_characteristics.sold_quantity) AS sold_quantity FROM "products" LEFT OUTER JOIN "product_characteristics" ON "product_characteristics"."product_id" = "products"."id" WHERE "products"."project_id" = $1 GROUP BY products.id [["project_id", 20]]
Please help me to write query through orm(to add where with dates and ordering) or write raw sql query.
I used pluck. It returns array of arrays (not array of hashes). It's no so good of course.
product_characteristics.date field is unique by scope product_id. But please give me two examples (with this condition and without it to satisfy my curiosity).
And I use postgresql and rails 4.2.x
P.S. By the way the ProductCharacteristic table will have a lot of records(mote than one million). Should I use postgresql table partitioning. Can it improve performance?
Thank you.
You can use select instead of count in that case, and the property will be accessible as product.sold_quantity
The query becomes
products = current_project.products.joins(:product_characteristics).group('products.id').select(:title, 'SUM(product_characteristics.sold_quantity) AS sold_quantity')
products.first.sold_quantity # => works
To order, you can just add an order clause
products = products.order(id: :asc)
or
products = products.order(id: :desc)
for instance
And for the where
products = products.where("created_at > ?", 2.days.ago)
for instance.
You can chain sql clauses after the first line, it does not matter cause the query will only be launched when you actually use the retrieved set.
And so you can also do stuff like
if params[:foo]
products = products.order(:id)
end

How do I write an SQL query whose where clause is contained in another query?

I have two tables, one for Customer and one for Item.
In Customer, I have a column called "preference", which stores a list of hard criteria expressed as a WHERE clause in SQL e.g. "item.price<20 and item.category='household'".
I'd like a query that works like this:
SELECT * FROM item WHERE interpret('SELECT preference FROM customer WHERE id = 1')
Which gets translated to this:
SELECT * FROM item WHERE item.price < 20 and item.category = 'household'
Example data model:
CREATE TABLE customer (
cust_id INT
preference VARCHAR
);
CREATE TABLE item (
item_id INT
price DECIMAL(19,4)
category VARCHAR
);
# Additional columns omitted for brevity
I've looked up casting and dynamic SQL but I haven't been able to figure out how I should do this.
I'm using PostgreSQL 9.5.1
I'm going to assume that preference is the same as my made up item_id column. You may need to tweak it to fit your case. For future questions like this it may pay to give us the table structures you are working with, it really helps us out!
What you are asking for is a subquery:
select *
from item
where item_id in (select
preference
from
customer
where id = 1)
What I would suggest though is a join:
select item.*
from item
join customer on item.item_id = customer.preference
where item.price<20 and
item.category='household'
customer.id = 1
I decided to change my schema instead, as it was getting pretty messy to store the criteria in preferences in that manner.
I restricted the kinds of preferences that could be specified, then stored them as columns in Customer.
After that, all the queries I wanted could be expressed as joins.

SQL Selecting rows with same value of foreign key

Does anyone know how to select all rows from a table with same value of FK without giving its value ? I have a database with warehouse. It has sectors and items of certain values in each sector . I want to select the sectors where overall value of items bigger than a certain number with a single query . And i want the query to be universal - it should sum up overall values of items in every sector of the warehouse ( without specyfing number of secotrs or how many sectors are there ) Anyone knows how to do it ? I don't need a full query, just a way to say my database that it to sum up all values in certain sectors. SectorID is the Foreign Key and Item is the table ( with ItemID as public key and Value as value of item )
I would make use of a combination of queries. Basically, this problem can be solved as below:
Assuming the presence of ID columns in both the Item and Sector tables. Let the value that acts as the threshold T (a certain number returned by a single query as stated above):
Use an inner query to select sector.sectorid, Item.itemid and Item.value by joining the Sector and Item tables on the Item.SectorID = Sector.SectorID Where Item.value > T
Sum(Item.value) on the result obtained from the inner query above and GROUP BY(SECTORID), GROUPBY(ITEMID).
You seem to want a group by query. This is pretty basic, so I assume you are pretty new to SQL:
select SectorId, sum(itemValue) as TotalItemValue
from warehouse w
group by SectorId
having sum(itemValue) > YOURVALUEHERE;
If you want the items in the sectors, then you can get that with a join or in:
select *
from warehouse w
where SectorId in (select SectorId
from warehouse
group by SectorId
having sum(itemValue) > YOURVALUEHERE
)

SQL table update from selection/join with multiple columns, only one column data needed

Firstly, I'm rather new to SQL and I've run into a roadblock. I'm using the Mimer SQL system.
I have three tables: "Transactions", roughly equivalent with a receipt total, which I want to update with data from a selection and the tables "item", containing prices and "sale", containing number of items and item IDs for a given transaction, which I have to join in order to get the data to update Transaction with.
SELECT sale.T_ID, SUM(sale.quantity * item.price) as total
FROM sale
INNER JOIN item
ON sale.I_ID = item.I_ID
GROUP BY T_ID
Gives me the desired data selection with the transaction IDs and the sum total for that transaction:
T_ID Amount
1 100
2 150
etc...
I want to update the Transaction table, which contains columns "T_ID" and "Total". I want to match the T_IDs and update the Total with the data from the corresponding Amount in the selection. The query:
UPDATE transaction SET total = (
SELECT total FROM (
SELECT sale.T_ID, SUM(sale.quantity * item.price) as total
FROM sale
INNER JOIN item
ON sale.I_ID = item.I_ID
GROUP BY T_ID)
WHERE transaction.T_ID=T_ID);
I can sense that the above statement is faulty, but unable to discern the problem. How should I construct the query?
Only select the SUM(sale.quantity * item.price) in your subquery and remove the select total one.
update Transaction
set total = (
select SUM(sale.quantity * Item.price)
from Sale
inner join Item on Sale.I_ID = Item.I_ID
where Sale.T_ID = Transaction.T_ID
)
That is what I would try out in SQL Server.
I would have prefered to have some sample data so that I can test it against my local SQL Server database in order to verify whether this statement does what is expected, though you're not using SQL Server, the idea is still the same.
EDIT #1
Though I do not fully understand why it does not overwrite values in the transaction.total column when a transaction is composed of several different items, your suggested query works.
The behaviour of the SUM function is to sum all targeted records resulting in only one scalar value for each Sale and Item rows. There can be only one sum, can it not?
That said, it multipies each resulting rows from the constraint, that is, for a particular transaction.
It selects both Sale and Item rows for this very transaction;
It then iterates through each of the resulting rows and multiply Sale.Quantity and Item.Price together, which is worth a value for each row;
Once a row is multiplied, its total is then added to a total which is stored somewhere in memory;
Once it has processed all the rows for that transaction, it comes out with a scalar value, which is the sum of all the rows in Sale and Item for that given transaction;
This SUM ends up to be this transaction's total.
In other words, the subquery "knows" for which transaction to sum which is filtered in the subquery itself. The Transaction table is accessible in the subquery as part of the main SQL statement. So, putting it in the where clause filters the rows from Sale and Item that will be later multiplied and additioned for the total.
Does this help you better understand this update statement?
Please feel free to ask your questions. =)