Active record query issues in Rails 3.2 - nginx

I have category model and category has many postings.
Problem: Sometimes postings are not visible under category in web even records are present in database
I investigated the query for the action in production enviroment by enabling config.log_level = :debug and restarted the
nginx passenger server. Now I can see the records under the category. I was unable to reproduce the same issue again and it occurs rarely.
Note:
I didn't change any code in the project. The same code behave differently.
Rails is 3.2.22. Nginx passenger(5.1.1)
Model are as follows
class Category < ActiveRecord::Base
has_many :postings, conditions: ['paid = ? AND start_date <= ? AND end_date >= ?', true, Date.current, Date.current]
end
class Posting < ActiveRecord::Base
searchkick
belongs_to :category
class << self
def payed
where paid: true
end
def activated
where :code => ""
end
def starts_on(date)
where "start_date <= ?", date
end
def ends_after(date)
where "end_date >= ?", date
end
def in_location(state,city)
where(stateid: state.id, cityid: city.id)
end
def not_deleted
where "active != false"
end
end
Postings controller
def index
#category = Category.find(params[:category_id])
postings = #category.postings.payed.activated.not_deleted.starts_on(Date.current).ends_after(Date.current).order(:created_at)
#postings = postings.in_location(current_state, current_city).page(params[:page])
end
From production.log, when accessing postings page /postings?category_id=25
Category Load (0.2ms) SELECT categories.* FROM categories
WHERE categories.id = 25 LIMIT 1
(0.4ms) SELECT COUNT(*) FROM postings WHERE
postings.category_id = 25 AND postings.paid = 1 AND
postings.code = '' AND postings.stateid = 44 AND
postings.cityid = 14823 AND (active != false) AND (paid = 1 AND
listing_start_date <= '2017-03-13' AND listing_end_date >=
'2017-03-13') AND (listing_start_date <= '2017-03-13') AND
(listing_end_date >= '2017-03-13')
CACHE (0. SELECT COUNT(*) FROM postings WHERE
postings.category_id = 25 AND postings.paid = 1 AND
postings.code = '' AND postings.stateid = 44 AND
postings.cityid = 14823 AND (active != false) AND (paid = 1 AND
listing_start_date <= '2017-03-13' AND listing_end_date >=
'2017-03-13') AND (listing_start_date <= '2017-03-13') AND
(listing_end_date >= '2017-03-13')
Posting Load (0.4ms) SELECT postings.* FROM postings WHERE
postings.category_id = 25 AND postings.paid = 1 AND
postings.code = '' AND postings.stateid = 44 AND
postings.cityid = 14823 AND (active != false) AND (paid = 1 AND
listing_start_date <= '2017-03-13' AND listing_end_date >=
'2017-03-13') AND (listing_start_date <= '2017-03-13') AND
(listing_end_date >= '2017-03-13') ORDER BY created_at LIMIT 10 OFFSET
0
The above set of queries did not pick any records; and after enabling debug mode and restart/touch the nginx server the same query fetched available records
Is the problem caused by active record query/ Nginx/ cache?
Please help me to resolve this issue.

Fixed the problem using Proc for association condition like
has_many :postings, conditions: proc { "payed = 1 AND start_date <= '#{Date.current.to_s(:db)}' AND end_date >= '#{Date.current.to_s(:db)}'"}
If you would have done association with dynamic condition like has_many :postings, conditions: ['paid = ? AND start_date <= ? AND end_date >= ?', true, Date.current, Date.current], there will be cases when the results you’ll get are not expected since the condition will have the day you started the Rails application and Date.current won’t be called again.
Thanks to Jose M.Gilgado. Reference: http://josemdev.com/articles/dynamic-conditions-associations-rails-3/

Related

Syntax error in MariaDB Stored Procedure With Parameter

Im trying to create a procedure for a railway database on phpmyadmin. In which the train number, train date, and category is read from the passenger. On the basis of the values provided by the passenger, corresponding record is retrieved from the Train_Status table. If the desired category is AC, then total number of AC seats and number of booked AC seats are compared in order to find whether ticket can be booked or not. Similarly, it can be checked for the general category. If ticket can be booked, then passenger details are read and stored in the Passenger table.
I have scratched my head on the procdure syntax but it is still giving an error. Tried changing syntax, removing the check condtion from variables but nothing seems to work.
The error it gives is
"#1064 - You have an error in your SQL syntax; check the manual that
corresponds to your MariaDB server version for the right syntax to use
near 'CHECK (train_number>=1 AND train_number<=5); DECLARE t_date
DATE; DECLA...' at line 6"
The mariadb version is 10.4.25
Here it is what I created
DELIMITER $$
CREATE PROCEDURE Booking (t_num int(1), t_date DATE, category varchar(10) )
BEGIN
DECLARE t_num int(1) CHECK (train_number>=1 AND train_number<=5);
DECLARE t_date DATE;
DECLARE category ENUM('AC', 'General');
DECLARE status ENUM('Confirmed', 'Waiting');
DECLARE getTrain CURSOR FOR
SELECT * FROM Train_Status
WHERE train_number = t_num AND train_date = t_date;
DECLARE trec Train_Status % ROWTYPE;
DBMS_OUTPUT.PUT_LINE('READING VALUES');
t_num := &t_num;
t_date := '&t_date';
category := '&category';
OPEN getTrain;
LOOP
FETCH FROM getTrain INTO trec;
EXIT WHEN getTrain % NOTFOUND;
IF(category = 'AC') THEN
IF(trec.t_acseats - trec.b_acseats) > 0 THEN
status := 'Confirmed';
DBMS_OUTPUT.PUT_LINE('Seat Confirmed');
ELSIF(trec.t_acseats - trec.b_acseats) > -2 THEN
status := 'Waiting';
DBMS_OUTPUT.PUT_LINE('Seat Waiting');
ELSE
DBMS_OUTPUT.PUT_LINE('Seat Not Available');
EXIT;
END IF;
IF status = 'Confirmed' OR status = 'Waiting' THEN
UPDATE Train_Status SET b_acseats = b_acseats + 1 WHERE
TrainNumber = t_num and TrainDate = t_date;
END IF;
ELSIF(category = 'General') THEN
IF(trec.t_genseats - trec.b_genseats) > 0 THEN
status := 'Confirmed';
DBMS_OUTPUT.PUT_LINE('Seat Confirmed');
ELSIF(trec.t_genseats - trec.b_genseats) > -2 THEN
status := 'Waiting';
DBMS_OUTPUT.PUT_LINE('Seat Waiting');
ELSE
DBMS_OUTPUT.PUT_LINE('Seat Not Available');
EXIT;
END IF;
IF status = 'Confirmed' OR status = 'Waiting' THEN
UPDATE Train_Status SET b_genseats = b_genseats + 1
WHERE TrainNumber = t_num and TrainDate = t_date;
END IF;
ELSE
DBMS_OUTPUT.PUT_LINE('Invalid Category');
END IF;
IF status = 'Confirmed' OR status = 'Waiting' THEN
INSERT INTO Passengers
VALUES ('&T_ID', t_num, t_date, '&Name', &Age, '&Sex', '&Address', status, category);
END IF;
END LOOP;
CLOSE getTrain;
END $$
DELIMITER ;
Check can't be used while declaring the variables. Only name and data type should be there.
Check cursor syntax from MariaDB documentation.
These two things will solve your 70% problems. Rest you can figure out.

Is it possible to replace sub-queries, used as a scalar value, with CTE?

I want to replace a long sub-query that return a scalar value or does not exist with just a short alias, because I place it 3 times to the UPDATE statement. Sub-query takes the last value in UncoveredLoss, if there is one, and the new UncoveredLoss value is calculated in the updated row depending on the last UncoveredLoss value.
It is a non-correlated query, but it is used in SELECT clause, not in the FROM clause. Maybe I should somehow modify the UPDATE statement in the trigger.
The working code:
CREATE TRIGGER Result
UPDATE OF Win ON Log
BEGIN
UPDATE Log
SET Profit = CASE
WHEN NEW.Win = 0
THEN - Stake
WHEN NEW.Win = 1
THEN Rate * Stake / 100
WHEN NEW.Win = 2
THEN 0
END
WHERE ID = OLD.ID;
UPDATE Log
SET SumProfit = (
SELECT Sum(Profit)
FROM (
SELECT StrategyAccountID
,Profit
FROM Log
WHERE DATE <= NEW.DATE
)
GROUP BY StrategyAccountID
HAVING StrategyAccountID = NEW.StrategyAccountID
)
WHERE ID = NEW.ID;
UPDATE Log
SET UncoveredLoss = CASE
WHEN EXISTS (
SELECT UncoveredLoss
FROM Log
WHERE DATE < NEW.DATE
AND StrategyAccountID = NEW.StrategyAccountID
ORDER BY DATE DESC LIMIT 1
)
AND (
SELECT UncoveredLoss
FROM Log
WHERE DATE < NEW.DATE
AND StrategyAccountID = NEW.StrategyAccountID
ORDER BY DATE DESC LIMIT 1
) + NEW.Profit < 0
THEN (
SELECT UncoveredLoss
FROM Log
WHERE DATE < NEW.DATE
AND StrategyAccountID = NEW.StrategyAccountID
ORDER BY DATE DESC LIMIT 1
) + NEW.Profit
WHEN NOT EXISTS (
SELECT UncoveredLoss
FROM Log
WHERE DATE < NEW.DATE
AND StrategyAccountID = NEW.StrategyAccountID
ORDER BY DATE DESC LIMIT 1
)
AND NEW.Profit < 0
THEN NEW.Profit
ELSE 0
END
WHERE ID = NEW.ID;
END;
The simple replacement of the sub-query using CTE not working:
CREATE TRIGGER Result
UPDATE OF Win ON Log
BEGIN
UPDATE Log
SET Profit = CASE
WHEN NEW.Win = 0
THEN - Stake
WHEN NEW.Win = 1
THEN Rate * Stake / 100
WHEN NEW.Win = 2
THEN 0
END
WHERE ID = OLD.ID;
UPDATE Log
SET SumProfit = (
SELECT Sum(Profit)
FROM (
SELECT StrategyAccountID
,Profit
FROM Log
WHERE DATE <= NEW.DATE
)
GROUP BY StrategyAccountID
HAVING StrategyAccountID = NEW.StrategyAccountID
)
WHERE ID = NEW.ID;
WITH Loss
AS (
SELECT UncoveredLoss
FROM Log
WHERE DATE < NEW.DATE
AND StrategyAccountID = NEW.StrategyAccountID
ORDER BY DATE DESC LIMIT 1
)
UPDATE Log
SET UncoveredLoss = CASE
WHEN EXISTS (Loss)
AND (Loss) + NEW.Profit < 0
THEN (Loss) + NEW.Profit
WHEN NOT EXISTS (Loss)
AND NEW.Profit < 0
THEN NEW.Profit
ELSE 0
END
WHERE ID = NEW.ID;
END;
Error: near "UPDATE": syntax error
It works nicely when I don't replace the sub-query, but when I try to use CTE it fails. I work in sql.el mode in Emacs.
Yeah, that can be cleaned up a lot. Consider something like:
CREATE TRIGGER Result UPDATE OF Win ON Log BEGIN
UPDATE Log
SET SumProfit = (SELECT sum(Profit)
FROM Log
WHERE Date <= NEW.Date AND StrategyAccountID = NEW.StrategyAccountID)
, UncoveredLoss = ifnull((SELECT min(UncoveredLoss + NEW.Profit, 0)
FROM Log
WHERE Date < NEW.Date AND StrategyAccountID = NEW.StrategyAccountID
ORDER BY Date DESC
LIMIT 1), 0)
WHERE ID = NEW.ID;
END;
which I'm pretty sure calculates the same results as yours. (Actual sample table definition and data to work with would be nice)
Also note that in recent Sqlite3 releases (3.25 and later), your SumProfit column can easily be computed on demand instead of taking up space in the table:
SELECT *
, sum(profit) OVER (PARTITION BY StrategyAccountID ORDER BY Date) AS SumProfit
FROM Log;

How can I set query_band for Block Level Compression using Aster's load_to_teradata function,

When you are loading a teradata table in bteq you can set the queryband for block level compression. This even works when you are using querygrid and inserting from a foreign server.
SET QUERY_BAND = 'BlockCompression=Yes;' UPDATE FOR SESSION;
My issue is that I am creating a table on an Aster system and then using the load to teradata function. I suspect there is a syntax call where I can set the query band as part of the load_to_teradata call but after searching the internet and through a reem of teradata documentation I haven't found anything yet.
-- Load Agg data for the YYYYMM to Teradta
SELECT SUM(loaded_row_count),SUM(error_row_count)
FROM load_to_teradata (
ON ( select
Cust_id
, cast(lst_cnf_actvy_dt_tm as date) as lst_cnf_actvy_dt
, cast(sum(str_cnt ) as INTEGER) as acct_open_brnch_use_cnt
, cast(sum(phone_cnt ) as INTEGER) as acct_open_phn_use_cnt
, cast(sum(mail_cnt ) as INTEGER) as acct_open_mail_use_cnt
, cast(sum(onlnchnl_cnt) as INTEGER) as acct_open_onln_use_cnt
, cast(sum(mblbnk_cnt ) as INTEGER) as acct_open_mbl_dvc_use_cnt
, cast(sum(acctopen_cnt) as INTEGER) as acct_open_trck_chnl_cnt
from <someDB>.<someTBL>
where acctopen_cnt > 0
and lower(lst_cnf_actvy_typ_cd) = 'acctopen'
and cast(lst_cnf_actvy_dt_tm as date) between
cast(substring('${YYYYMM}' from 1 for 4) || '-' || substring('${YYYYMM}' from 5 for 2) || '-01' as date) and
cast((cast(substring('${YYYYMM}' from 1 for 4) || '-' || substring('${YYYYMM}' from 5 for 2) || '-01' as date) + interval '1 month') - interval '1 day' as date)
and (str_cnt > 0 or phone_cnt > 0 or mail_cnt > 0 or onlnchnl_cnt > 0 or mblbnk_cnt > 0)
group by 1,2 )
TDPID('TD_RDBMS_C2T') USERNAME('${c2tUID}') PASSWORD('${c2tPWD}') ${LDAP_IND_AST_C2T}
TARGET_TABLE ( 'C2T.t_yyyymm_agg' ) LOG_TABLE ('C2T.t_yyyymm_aggLOG')
MAX_SESSIONS(120));
Was able to get the syntax for the load_to_teradata options. You can see the query_band_sess_info argument after max_sessions and before query_timeout...
load_to_teradata(
ON (source query)
TDPID('tdpid')
TARGET_TABLE('fully-qualified table name')
[ERROR_TABLES('error table'[, 'unique constraint violation table'])]
[LOG_TABLE('table name')]
Teradata QueryGrid: Aster-Teradata Connector
Loading Data From Aster Database to Teradata
Aster Database User Guide for Aster Appliances 301
[USERNAME('username')]
[PASSWORD('password')]
[LOGON_MECHANISM('TD2' | 'LDAP' | 'KRB5')]
[LOGON_DATA('mechanism-specific logon data')]
[ACCOUNT_ID('account-id')]
[TRACE_LEVEL('trace-level')]
[NUM_INSTANCES('instance-count')]
[START_INSTANCE('start-instance')]
[MAX_SESSIONS('max-sessions-number')]
[QUERY_BAND_SESS_INFO('key1=value1;key2=value2;...')]
[QUERY_TIMEOUT('timeout-in-seconds')]
[AUTO_TUNE_INSTANCES('yes'|'no')]
[WORKINGDATABASE(‘dbname’)]
[DIAGNOSTIC_MODE('All'|['GetCOPEntries','CheckConnectivity',
'CheckAuthentication','GetTPTSessions',
'TargetTableOrQuerySchema'])])
);

How can i simplify this LINQ-To-Entity query, and make it dynamic

I have this query for getting data through Entity Framework, which works today. Thing is, i want to create the query dynamically, i.e build it up in blocks, but i can't figure out how exactly to do it. I believe if i can somehow save one of the values that i retrieve in the beginning i can do it, but now i retrieve it twice (probably a bit slow as well? Unless the compiler fixes it before quering). Makes sense? Here is the LINQ:
from d in db.trains
where d.cancelled
&& d.station == toStation
&& d.date >= fromDate.Date
&& d.date <= toDate.Date
&& (from k in db.trains
where
k.date == d.date
&& k.trainId == d.trainId
&& k.stationId == fromStation
&& k.position <= d.position
select k.trainId).Contains(d.trainId)
select new
{
trainId = d.trainId,
date = d.date,
arrival = d.arrival,
departure = (from k in db.trains
where
k.date == d.date
&& k.trainId == d.trainId
&& k.stationId == fromStation
&& k.position <= d.position
select k.departure).FirstOrDefault()
}
);
So you see, in order to get the departure, i have to retrieve the same thing again. So what i'm asking is can i save the object in the first query and then retrieve it later somehow? I can't get the syntax working.
The database looks something like this:
trainId stationId date arrival departure position
1 99 2010-10-11 10:00 10:10 1
1 98 2010-10-11 11:20 11:30 2
1 47 2010-10-11 12:30 12:40 3
2 99 2010-10-10 15:00 15:10 5
etc
So bascially, i need to retrieve two objects from the db, where the first one has stationId x and the other one has stationId y and both have the same date and trainId, and they have to be in the proper order, based on position (trains go both ways, but with different trainId's).
Also, i would like to do be able to build this query dynamically, like this:
var trains = from d in db.trains
select d;
if (id > 0)
trains = trains.Where(p => p.trainId == id);
if (date != DateTime.MinValue)
trains = trains.Where(p => p.date == date);
var items = (from train in trains).ToList();
I.e based on if various variables have values.
You can use the let statement to store local variables and reuse them later
Something like this:
from d in db.trains
where d.cancelled
&& d.station == toStation
&& d.date >= fromDate.Date
&& d.date <= toDate.Date
let departures = (from k in db.trains
where
k.date == d.date
&& k.trainId == d.trainId
&& k.stationId == fromStation
&& k.position <= d.position
select k)
where departures.Select(d => d.trainId).Contains(d.trainId)
select new
{
trainId = d.trainId,
date = d.date,
arrival = d.arrival,
departure = departures.Select(d => d.departure).FirstOrDefault()
}
);

Problems with Recordset Filter

I'm having trouble with a filter on an ADO Recordset in legacy ASP Classic code, and I'm trying to understand if what I'm trying to do is not supported, or if I'm just doing it wrong.
I have a recordset of Items, and they have a Status of 1 (active) or 0 (inactive), and an optional End_Date. In my administrative user interface, I have a control to show all items or only those that should be displayed to end-users: Status = 1 AND ( End_Date is null OR End_Date > Date() )
To implement that logic, I tried:
rs.Filter = "Status = 1 AND ( End_Date = null OR End_Date > #" & Date() & "# )"
but I get
ADODB.Recordset (0x800A0BB9)
Unknown runtime error
After much fooling around, it seems that ADO doesn't like the grouping parens around the End_Date conditions in combination with the AND condition. If I take the parens out, this works:
rs.Filter = "Status = 1 AND End_Date = null OR End_Date > #" & Date() & "#"
But that's just an accident -- it looks like the filter conditions are evaluated in order, and so I get the results I want. If I change the AND to OR, the parens work:
rs.Filter = "Status = 1 OR ( End_Date = null OR End_Date > #" & Date() & "# )"
But of course that logic is wrong -- it shows Active but expired items.
Strangely, if I move the conditions around, it breaks again:
rs.Filter = "End_Date = null OR Status = 1 AND End_Date > #" & Date() & "# "
crashes with the same ADODB error.
I can't seem to predict what will and won't work, and the docs I've read are very sketchy on the syntax expected (it's not pure T-SQL!), the limitations, etc. and all the examples I've seen have at most two conditions. I don't think my conditions are all that complex. Can anyone tell me if what I'm trying to do is supported, if there's a better way to do it, or point me to comprehensive docs and samples that match this kind of logic?
Thanks!
ADO Recordset Object Filter Property:
There is no precedence between AND and OR. Clauses can be grouped within parentheses. However, you cannot group clauses joined by an OR and then join the group to another clause with an AND, like this:
(LastName = 'Smith' OR LastName =
'Jones') AND FirstName = 'John'
Instead, you would construct this
filter as:
(LastName = 'Smith' AND FirstName =
'John') OR
(LastName = 'Jones' AND FirstName =
'John')
So you would have to construct your filter like this:
rs.Filter = "( Status = 1 AND End_Date = null ) OR ( Status = 1 AND End_Date > #" & Date() & "# )"
I know that you are working with legacy code and probably other things are working, but how do you open the recordset in this specific page? Are you using some constant defined in adovbs.inc?
For example:
rs.Open "SELECT * FROM table1", db, adOpenStatic, adLockPessimistic
What happens when you try this...
Dim strToday
strToday = Now()
rs.Filter = "Status=1 AND (End_Date = null OR End_Date > """ & strToday & """)"

Resources