I'm creating a table to store rules for another selects and it has the following design:
id
column
operator
value
next_rule_id
next_operator
1
mail
contains
#gmail.com
2
OR
2
mail
contains
#hotmail.com
5
AND
3
city
equals
NY
5
AND
4
mail
contains
jolie#
3
AND
5
city
equals
NY
4
null
6
user_id
greater
10
null
null
I need to select 1 rule id and return all rows based on next_rule_id
Here are some examples:
selecting rule id = 1 would return
1 mail contains #gmail.com 2 OR
2 mail contains #hotmail.com 5 AND
5 city equals NY 4 null
selecting rule id = 4 would return
4 mail contains jolie# 3 AND
3 city equals NY 5 AND
5 city equals NY 4 null
selecting rule id = 6 would return
6 user_id greater 10 null null
SOLUTION 1
I've managed to do that with a temporary table and one loop. But I think there is better approaches to do that.
If anyone knows how to do that in a better way I would appreciate your help.
SOLUTION 2
I created this procedure that uses a loop too.
BEGIN
SET #id = 1; -- hardcoded first id
SET #rules = '';
SET #next_id = NULL;
loop1: LOOP
SET #count = #count + 1;
SELECT next_rule_id INTO #next_id FROM filter_rules WHERE id = #id;
SET #rules = CONCAT(#rules, ',', #id);
SET #id = #next_id;
IF #id IS NULL THEN
LEAVE loop1;
END IF;
END LOOP loop1;
SELECT * FROM filter_rules WHERE FIND_IN_SET(filter_rules.id, #rules);
END
I've been working with the WRDS/CRSP dataset (a stock price database maintained by UPenn for academic research). I've been downloading the data in Python and inserting it into my local MySQL database.
The data looks like this and has primary key on (quote_date, security_id):
quote_date security_id tr accum_index
10-Jan-86 10002 null 1000
13-Jan-86 10002 -0.026595745 973.4042548
14-Jan-86 10002 0.005464481 978.7234036
15-Jan-86 10002 -0.016304348 962.7659569
16-Jan-86 10002 0 962.7659569
17-Jan-86 10002 0 962.7659569
20-Jan-86 10002 0 962.7659569
21-Jan-86 10002 0.005524862 968.0851061
22-Jan-86 10002 -0.005494506 962.765957
23-Jan-86 10002 0 962.765957
24-Jan-86 10002 -0.005524862 957.4468078
27-Jan-86 10002 0.005555556 962.7659569
28-Jan-86 10002 0 962.7659569
29-Jan-86 10002 0 962.7659569
30-Jan-86 10002 0 962.7659569
31-Jan-86 10002 0.027624309 989.3617013
3-Feb-86 10002 0.016129032 1005.319148
4-Feb-86 10002 0.042328041 1047.872338
5-Feb-86 10002 0.04568528 1095.744679
I need to calculate the accum_index column which is basically an index of the total return of the stock and is calculated as follows:
accum_index_t = accum_index_{t-1} * (1 + tr_t)
The table has 80m rows. I've wrote some code to iterating through every security_id and calculate a cumulative product, like so:
select #sid := min(security_id)
from stock_prices;
create temporary table prices (
quote_date datetime,
security_id int,
tr double null,
accum_index double null,
PRIMARY KEY (quote_date, security_id)
);
while #sid is not null
do
select 'security_id', #sid;
select #accum := null;
insert into prices
select quote_date, security_id, tr, accum_index
from stock_prices
where security_id = #sid
order by quote_date asc;
update prices
set accum_index = (#accum := ifnull(#accum * (1 + tr), 1000.0));
update stock_prices p use index(PRIMARY), prices a use index(PRIMARY)
set p.accum_index = a.accum_index
where p.security_id = a.security_id
and p.quote_date = a.quote_date;
select #sid := min(security_id)
from stock_prices
where security_id > #sid;
delete from prices;
end while;
drop table prices;
But this is too slow, it's taking about a minute per security on my laptop and it will take years to calculate this series. Is there a way to vectorise this?
Cheers,
Steve
If you're using MySQL 8, you could use window functions to create the cumulative product. Unfortunately, there is no PROD() aggregate / window function in any SQL database I'm aware of, but you can emulate it using EXP(SUM(LOG(factor))):
SELECT
quote_date,
security_id,
tr,
1000 * (EXP(SUM(LOG(1 + COALESCE(tr, 0)))
OVER (PARTITION BY security_id ORDER BY quote_date)))
AS accum_index
FROM stock_prices
dbfiddle here.
If you're using MySQL 5, you can emulate this function multiplying current with last tr line by line. After that we take the accumulated value of the last line.
tr is percentual value, right now?
So lets add 1 to each tr.
The first stored value will be neutral 1.
Try this:
SET #variation = 1;
SET #row_number = 0;
SELECT accumulateTr
FROM
(SELECT
#row_number := (#row_number + 1) AS rowNumber,
#variation := (1 + variation) * #variation AS accumulateTr
FROM
prices) accumulatedTrs
ORDER BY rowNumber DESC
LIMIT 1;
I need to get the maximum value +1 for a field, if that filed as the 0000 value.
IF
(acc_id = 0000)
FROM
crm_accounts;
INSERT
INTO
crm_accounts(acc_id)
SELECT MAX
(acc_id) + 1
FROM
crm_accounts;
I think you're looking to do an UPDATE statement...
This should get it done for you:
SELECT #id := MAX(acc_id) FROM crm_accounts;
UPDATE crm_accounts
SET acc_id = #id := #id + 1
WHERE acc_id = 0000;
I have
Array ( [406] => 1 [407] => 3 [408] => 2 [409] => 7 [410] => 1 )
run as mysql query
UPDATE counter SET total = 1 WHERE id = 406;
UPDATE counter SET total = 3 WHERE id = 407;
UPDATE counter SET total = 2 WHERE id = 408;
UPDATE counter SET total = 7 WHERE id = 409;
UPDATE counter SET total = 1 WHERE id = 410;
I can only optimized query above by grouping same total value as below:
UPDATE counter
SET total = 1
WHERE name IN (406, 410);
Is there any way to optimize it better, rather than execute (loop) the update query one by one.
You need this:
UPDATE counter SET total = CASE
WHEN id = 406 THEN 1
WHEN id = 407 THEN 3
WHEN id = 408 THEN 2
WHEN id = 409 THEN 7
WHEN id = 410 THEN 1
END
you can use key value pair to update like below
UPDATE counter SET total = '".$value."' WHERE id = '".$key."';
I have 7 SQL Query to do a task like this :
1. UPDATE Customer SET CustomerService = 'perta' WHERE FirstName = 'john';
2. UPDATE Customer SET Flag = 1 WHERE OrderNum BETWEEN 2 AND 29;
3. UPDATE Customer SET PurchaseNum = PurchaseNum + 60 WHERE OrderNum BETWEEN 2 AND 29;
4. UPDATE Customer SET OrderNum = OrderNum + 60 WHERE OrderNum BETWEEN 2 AND 29;
5. UPDATE Customer SET PurchaseNum = PurchaseNum - 28 WHERE (PurchaseNum > 29 AND PurchaseNum <= 89) AND (Flag <> 1);
6. UPDATE Customer SET OrderNum = OrderNum - 28 WHERE (OrderNum > 29 AND OrderNum <= 89) AND (Flag <> 1);
7. UPDATE Customer SET Flag = 0 WHERE OrderNum BETWEEN 62 AND 89;
is it possible to 'compress' those SQL Queries into 1 Query?
because I'm afraid that user cancel the process by pressing the ESC button (after he/she press the SUBMIT button), those sequence will be broken in the middle and my table will be messy as well.
If you are using MySQL then see this link it shows you how to implement transaction in MySQL.
http://dev.mysql.com/doc/refman/5.5/en/commit.html
Transaction helps us in many scenario and you are handling one of them where you want to update multiple database tables.