Coldfusion CFScript Query with MySQL Assignment Operator - mysql

I want to select currentrow as part of my query - I know I can loop over queries and get the currentrow variable, but I'm doing a QoQ before I use the rows and I want to keep the original rows, e.g.
//Original query
1, Audi
2, BMW
3, Skoda
//QoQ
1, Audi
3, Skoda
This is the code I've got:
q = new Query( datasource = application.db.comcar );
q.setSQL('
SELECT make, #rownum := #rownum +1 AS `rownumber`
FROM cars, ( SELECT #rownum :=0 )
LIMIT 10
');
r = q.execute().getResult();
But it's throwing the following error:
Parameter '=' not found in the list of parameters specified
SQL: SELECT make, #rownum := #rownum + 1 AS `rownumber` FROM cars, ( SELECT #rownum :=0 ) LIMIT 10
This will work in cfquery but I'd like to use it in CFScript. Is there an alternative to using := or some way of escaping this in the query.

It looks like this is a bug in Coldfusion. I could change my code to use cfquery but I'd rather not mix script and tags in my page.
So my workaround was is as follows:
/*
* based on the existing query 'tmpFields'
*/
// build array of row numbers
arrRowNumbers = [];
cntRowNumbers = tmpFields.recordCount;
for( r = 1; r <= cntRowNumbers; r++ ) {
arrayAppend( arrRowNumbers, r );
}
// add a new column with the new row number array
queryAddColumn( tmpFields, "fieldNumber", "integer", arrRowNumbers );

Related

mysql works fine after first time

I have a strange problem which is when I run the sql command first time it shows wrong result, but when I run the same code for second time the result is correct.
The wrong result is:
The expected result is:
the sql command is:
SELECT srNumber, end_on, start_on, teamEntityId
FROM (
SELECT srNumber, end_on, start_on, teamEntityId,
#lastrow := IF(#sr_Number = srNumber, #lastrow + 1,
IF(#sr_Number := srNumber, 1, 0)) AS lastrow
FROM assign
CROSS JOIN (SELECT #lastrow := 0, #sr_Number = '') AS vars
ORDER By srNumber, assignId DESC) AS t
WHERE t.lastrow = 1 AND t.teamEntityId = '00000168752ac161-02420aff00230001'
In more recent versions of MySQL, you need to order the data before using variables. So replace:
FROM assign
with:
FROM (SELECT a.* FROM assign a ORDER BY srNumber, assignId DESC) a
I would like to thank Alex and Salman A who solved the problem which is:
replace the below code
#sr_Number = ''
to
#sr_Number := ''

sql rank row results

I"m trying to add a new col that shows the rank (or sequence) of row results by date.
I've written:
SELECT
#row_number:=(CASE
WHEN #member_id = lh.member_id and lc.ladder_advocacy is not null
THEN #row_number + 1
when #member_id = lh.member_id and lc.ladder_advocacy is null then "null"
ELSE 1 /* there is an error here - i need it to return a 1 if not null, then 2 for the 2nd instance, etc */
END) AS rank_advocacy,
#member_id:=lh.member_id AS member_id,
lh.ladder_change,
lc.name,
lc.ladder_advocacy,
lc.ladder_elected,
lc.ladder_policy,
lc.ladder_engagement,
lc.ladder_newventure,
lc.ladder_collective,
lc.is_trigger
FROM
leenk_ladder_history AS lh
LEFT JOIN
leeds_so.leenk_ladder_config AS lc ON lh.ladder_config_id = lc.id
WHERE
ladder_change = 1 AND trigger_active = 1
ORDER BY member_id, trigger_event_date DESC;
There is an error at row 4, and I'm not sure how to fix it. For the first result, I want to return 1. for the second results, I want to return #row_number + 1. Third result, #row_number+2 (etc).
How do I achieve this?
I don't understand how the condition lc.ladder_advocacy is not null is being used. However, the basic structure is:
SELECT (#row_number = IF(#member_id = lh.member_id, #row_number + 1
IF(#member_id := lh.member_id, 1, 1)
)
) as rank_advocacy,
lh.ladder_change,
. . .
Some really important points:
You need to assign #member_id and #row_number in the same expression. MySQL (as with all other databases) does not guarantee the order of evaluation of expressions.
In more recent versions of MySQL, I think the ORDER BY needs to go in a subquery, with the variable expressions in the outer query.

Determine if date range is contained in another range in MySQL

I'm looking for a method to do this in a "clean" way (not 3..n cross JOINS), just want to know if it's possible to do it in sql, if not I'll go for another solution.
Will use numbers instead of dates for simplification
I have n rows with n tasks and n items
task item start end
1 1 1 5
1 2 2 6
1 3 0 4
1 4 8 10
In this case I'm looking to use the min(start) max(end) of the overlapping dates so the result will be:
task item start end
1 1,2,3 0 6
1 4 8 10
Any ideas of how to resolve it in sql? is like a challenge, if can't do it this way I'll go to python.
Thank you
This similar to the problem I answered here, and similar data "island" problems. However, it is more complicated in your case as the identification of the "islands" will need to be calculated from more than just the record immediately prior.
It will end up looking something like this:
SET #iEnd = -1; /* init value should be something you don't expect to see */
SET #task = -1; /* init value should be something you don't expect to see */
SET #isNewIsland = 0 /* init value doesn't actually matter */;
SET #i = 0;
SELECT islandNum
, GROUP_CONCAT(item ORDER BY item) AS items
, MIN(start) AS iStart
, MAX(end) AS iEnd
FROM (
SELECT #isNewIsland := IF(#task <> task OR start > #iEnd, 1, 0)
, #task := task, item, start, end
, #i := IF(#isNewIsland = 1, #i + 1, #i) AS islandNum
, #end := IF(#isNewIsland = 1, end, GREATEST(end, #iEnd))
FROM ( /* Session(#) variables evaluation can be a bit unpredictable
the subquery helps guarantee ordering before evaluation */
SELECT task, item, start, end
FROM theTable
ORDER BY task, start, end
) AS subQ
) AS subQ 2
some are not fond of needing the separate, preceding SET statements; to avoid the need, replace ) AS subQ with
) AS subQ, (SELECT #iEnd := -1, #task := -1, #isNewIsland := 0, #i := 0) AS sInit

Laravel Eloquent skip every N th row

I have a large DB, with 50000+ rows, i'm trying to get all rows but with skipping every 50 rows for example.
I tried this from Laravel documentation: Offset & Limit
$users = DB::table('users')->skip(10)->take(5)->get();
But this will only skip the first 10 rows and get the next 5 rows. I can't find Eloquent solution to this problem.
Has anybode solve this before?
Solved using raw query:
return DB::select(DB::raw('
SELECT dateTime, row1, row2
FROM (
SELECT #row := #row +1 AS rownum, dateTime, row1, row2
FROM (
SELECT #row :=0
) r, users
) ranked
WHERE rownum % 50 = 0'));
It's much faster solution then #disf.asia suggestion.
You have to use a loop.
$start = 0;
$skip = 50;
$take = 1;
$all = array();
do {
$partial = User::skip($start++ * $skip)->take($take)->get();
$all = array_merge($all, (array) $partial);
} while (count($partial) > 0);
this will take 1 row every 50skipped rows, so 1st, 51th, 100th ... till the end of the table

mysql create view with mysql query that contains variable

I have the below syntax that I want to use to create a MySQL view:
create view `ViewName` as (select
v_starting.callingname,
v_starting.geofence,
v_starting.`updatetime`,
#lastGroup := #lastGroup + if( #lastAddress = v_starting.geofence
AND #lastVehicle = v_starting.callingname, 0, 1 ) as GroupSeq,
#lastVehicle := v_starting.callingname as justVarVehicleChange,
#lastAddress := v_starting.geofence as justVarAddressChange
from
v_starting,
( select #lastVehicle := '',
#lastAddress := '',
#lastGroup := 0 ) SQLVars
order by
v_starting.`updatetime` )
This fails with error:
#1351 - View's SELECT contains a variable or parameter
How can I get around this? Thanks a million.
As documented under CREATE VIEW Syntax:
A view definition is subject to the following restrictions:
[ deletia ]
The SELECT statement cannot refer to system or user variables.
Think you would need to do this using a subselect to count the records.
Something like this:-
SELECT v_starting.callingname,
v_starting.geofence,
v_starting.`updatetime`,
Sub1.PrevRecCount ASGroupSeq
FROM v_starting
INNER JOIN (SELECT a.updatetime, COUNT(DISTINCT b.callingname, b.geofence ) AS PrevRecCount
FROM v_starting a
LEFT OUTER JOIN v_starting b
ON a.updatetime > b.updatetime
AND a.callingname != b.callingname
AND a.geofence != b.geofence
GROUP BY a.updatetime) Sub1
Not 100% sure about this as I am dubious about how you are ordering things to get your count presently.
for variable using, try to use a stored procedure or a custom function