I'm using php pdo with SQL Server Native Client 11.0 as the driver.
Obiously I do cannot use LIMIT clause as it is proprietary and in trying to workarounf selecting ranges of rows I keep hitting issues.
My setup as follows :
$statement = "SELECT ROW_NUMBER() OVER (ORDER BY USERS.name DESC) AS RowNum, CASE.no, CASE.type, CASE.date, CASE.ju, USERS.name, TBRLMF.rd_rl_description FROM dbo.CASE INNER JOIN dbo.USERS ON dbo.CASE.no = dbo.USERS.case_no INNER JOIN dbo.CMSTBRLMF ON dbo.USERS.relationship = dbo.TBRLMF.code ";
if($exact == 'checked'){
$exact = '=';
}else{
$exact = 'LIKE';
}
if($searchtype == 'users'){
$statement .= " WHERE USERS.name $exact '%$searchstring%'";
}else{
$statement .= " WHERE USERS.no $exac '%$searchstring%'";
}
$statement .= " AND RowNum BETWEEN :offset AND :max";
$statement = $dbh->prepare($statement);
$statement->bindParam(':offset', $offset, PDO::PARAM_INT);
$statement->bindParam(':max', $max, PDO::PARAM_INT);
and as long as I do not include the line of code :
$statement .= " AND RowNum BETWEEN :offset AND :max";
It works fine but gives me all the data.
When that line is included I recieve the following error :-
caught exception 'PDOException' with message 'SQLSTATE[42S22]: Column not found: 207 [Microsoft][SQL Server Native Client 11.0][SQL Server]Invalid column name 'RowNum'. (SQLExecute[207] at ext\pdo_odbc\odbc_stmt.c:254)' in C:\pub\test\Classes\Core.php:44
I am at a loss and MSSQL is new to me.
Help much appreciated.
The predicate on that column can't be in a WHERE clause. (The predicates in the WHERE clause are evaluated when the rows are accessed; the value of that expression (analytic function) isn't available until after the rows are accessed.
You may be able to reference the column alias in a HAVING clause:
" HAVING RowNum BETWEEN ... ";
You can't use COLUMN ALIAS (RowNum in your case) in WHERE clause. Rather change your query using derived table like below
SELECT * FROM
(
SELECT ROW_NUMBER() OVER (ORDER BY USERS.name DESC) AS RowNum,
CASE.no,
CASE.type,
CASE.date,
CASE.ju,
USERS.name,
TBRLMF.rd_rl_description
FROM dbo.CASE
INNER JOIN dbo.USERS
ON dbo.CASE.no = dbo.USERS.case_no
INNER JOIN dbo.CMSTBRLMF
ON dbo.USERS.relationship = dbo.TBRLMF.code
WHERE USERS.name LIKE '%string%'
AND USERS.no LIKE '%string%'
) X
WHERE RowNum BETWEEN 1 AND 10;
EDIT:
You can also use CTE (Common Table Expression) to get around this like below
Create the CTE
WITH NEWCTE AS
(
SELECT ROW_NUMBER() OVER (ORDER BY USERS.name DESC) AS RowNum,
CASE.no,
CASE.type,
CASE.date,
CASE.ju,
USERS.name,
TBRLMF.rd_rl_description
FROM dbo.CASE
INNER JOIN dbo.USERS
ON dbo.CASE.no = dbo.USERS.case_no
INNER JOIN dbo.CMSTBRLMF
ON dbo.USERS.relationship = dbo.TBRLMF.code
WHERE USERS.name LIKE '%searchstring%'
AND USERS.no LIKE '%searchstring%'
)
Query the CTE
SELECT *
FROM NEWCTE
WHERE RowNum BETWEEN 1 AND 10
Related
when fetching data from database php say undefined index for that row which is count(*) as name that name it not defined
SELECT location.location_name,
employers.emp_name,
(SELECT COUNT(present.present_date) AS present_days
from present
WHERE present_status='م' AND present.emp_id=employers.emp_id AND present.present_date between '$date1' AND '$date2') ,
(SELECT COUNT(present.present_status) AS absent_days
from present
WHERE present_status='غ' AND present.emp_id=employers.emp_id AND present.present_date between '$date1' AND '$date2'),
(SELECT COUNT(present.present_status) AS permission_absent_days
from present
WHERE present_status='غب' AND present.emp_id=employers.emp_id AND present.present_date between '$date1' AND '$date2'),
(SELECT band.band_name AS training
from band
WHERE band_name='NoTraining' AND band.emp_id=employers.emp_id AND band.band_date between '$date1' AND '$date2'),
(SELECT COUNT(band.band_name)AS employers_band
from band
WHERE band.emp_id=employers.emp_id AND band.band_date between '$date1' AND '$date2')
FROM `present`, `employers`,`location`,`band`
WHERE present.emp_id = employers.emp_id AND location.location_id = employers.location_id
GROUP BY employers.emp_name
ORDER BY employers.emp_name ASC
The alias assignment should be after the closing paren of the subquery in the SELECT list
SELECT ...
, ( SELECT ... AS foo FROM ... WHERE ... ) AS col_name
-- ^^^^^^^^^^^
FROM
The alias foo assigned inside the subquery doesn't matter to the outer query. What matters to the outer query is the alias assigned to the expression in the SELECT list of the outer query, col_name.
(We can run the query in mysql command line client, and see the assigned to the column in the resultset. Or in the PHP code, we could inspect/vardump the array returned from the fetch.)
Some other issues appear to be semi-Cartesian product, multiple rows returned from multiple child tables cross joined together. Seems to be some join conditions missing.
I recommend ditching the old-school comma syntax for the join operation and using the JOIN keyword instead.
FOLLOWUP
The suggestion above (assigning an alias to the subquery expression in the SELECT list of the outer query, may "work" , but I think there's significantly more wrong with the query.
With the correlated subqueries in the SELECT list, I don't think it's necessary to perform joins to band and present in the outer query. That's going to produce wonky results, when multiple rows are returned and cross joined. And if no matching row is returned from band or present, a row is going to missing from the resultset.
It looks to me (and I'm just guessing because we don't have a specification for what the query is supposed to return) ...
It looks to me like the intent is to return a result equivalent to the one returned by a query of this pattern:
SELECT l.location_name
, e.emp_name
, ( SELECT COUNT(pd.present_date) AS present_days
FROM present pd
WHERE pd.emp_id = e.emp_id
AND pd.present_status = '?'
AND pd.present_date BETWEEN '$date1' AND '$date2'
) AS present_days
, ( SELECT COUNT(ad.present_status)
FROM `present` ad
WHERE ad.emp_id = e.emp_id
AND ad.present_status = '?'
AND ad.present_date BETWEEN '$date1' AND '$date2'
) AS absent_days
, ( SELECT COUNT(pa.present_status)
FROM `present` pa
WHERE pa.emp_id = e.emp_id
AND pa.present_status = '??'
AND pa.present_date BETWEEN '$date1' AND '$date2'
) AS permission_absent_days
, ( SELECT MAX(tr.band_name)
FROM `band` tr
WHERE tr.emp_id = e.emp_id
AND tr.band_name = 'NoTraining'
AND tr.band_date BETWEEN '$date1' AND '$date2'
) AS training
, ( SELECT COUNT(eb.band_name)
FROM `band` eb
WHERE eb.emp_id = e.emp_id
AND eb.band_date BETWEEN '$date1' AND '$date2'
) AS employers_band
FROM `employers` e
JOIN `location` l
ON l.location_id = e.location_id
ORDER
BY e.emp_name ASC
I'm trying to export a mysql query table to an excel file. I have it working on another page on my site however it seems to be having trouble with this particular query.
I'm getting this error:
Warning: PDO::query() [pdo.query]: SQLSTATE[42S22]: Column not found: 1054
Unknown column 'u2.confirmed_cash' in 'field list' in
/home2/jtdsdevc/public_html /rbk/usage-v3/inc/excel-exporter
/MySqlExcelBuilder.class.php on line 130
This is my code.
// Setup the SQL Statements
$sql_statement = getReport($idLeague, $idTeam);
function getReport($idLeague, $idTeam){
global $connect;
$sql = "
SELECT idPlayer AS id,
(SELECT CONCAT_WS(' ', location, name) FROM `team` WHERE `team`.id = u.idTeam) AS team,
(SELECT CONCAT_WS(' ', first_name, last_name) FROM `player` WHERE `player`.id = u.idPlayer) AS name,
(SELECT u2.confirmed_cash FROM `usage` u2 WHERE u.idPlayer = u2.idPlayer ORDER BY date DESC LIMIT 1) AS total_cash,
(SELECT u2.confirmed_product FROM `usage` u2 WHERE u.idPlayer = u2.idPlayer ORDER BY date DESC LIMIT 1) AS total_product,
max(date) AS last_entry
FROM `usage` u INNER JOIN `team` t ON u.idTeam =t.id INNER JOIN `league` l ON t.idLeague =l.id WHERE (t.idleague =".$idLeague." or l.pID =".$idLeague." )
";
return $sql;
}
// Add the SQL statements to the spread sheet
$mysql_xls->add_page('Report',$sql_statement);
// Get the spreadsheet after the SQL statements are built...
$phpExcel = $mysql_xls->getExcel(); // This needs to come after all the pages have been added.
....
That's where the error happens. The exact line in the MySqlExcelBuilder.class.php file is:
if ($sh = $this->pdo->query($sql))
The $sql variable above comes out to be
SELECT idPlayer AS id,
(SELECT CONCAT_WS(' ', location, name) FROM `team` WHERE `team`.id = u.idTeam) AS team,
(SELECT CONCAT_WS(' ', first_name, last_name) FROM `player` WHERE `player`.id = u.idPlayer) AS name,
(SELECT u2.confirmed_cash FROM `usage` u2 WHERE u.idPlayer = u2.idPlayer ORDER BY date DESC LIMIT 1) AS total_cash,
(SELECT u3.confirmed_product FROM `usage` u3 WHERE u.idPlayer = u3.idPlayer ORDER BY date DESC LIMIT 1) AS total_product,
max(date) AS last_entry
FROM `usage` u
INNER JOIN `team` t ON u.idTeam =t.id
INNER JOIN `league` l ON t.idLeague =l.id
WHERE (t.idleague =1 or l.pID =1 )
Edit: It is also worth noting that the query by itself works fine in phpMyAdmin.
Problem Solved! I was calling the wrong database, rookie mistake.
I'm trying to implement a LIMIT OFFSET query using MS SQL for the purpose of implementing Pagination to my products on a website together with PHP and PDO, but I get the following error: "Invalid column name"
My query
SELECT OITM.ItemCode,OITM.ItemName,ITM1.Price ,
OITM.CardCode,ROW_NUMBER() OVER (ORDER BY OITM.ItemName DESC) AS RNumber
FROM OITM INNER JOIN OCRD ON OCRD.CardCode = OITM.CardCode
INNER JOIN ITM1 ON OITM.ItemCode = ITM1.ItemCode
WHERE OITM.frozenFor='N' AND PriceList=1 AND U_Publish='Y'
AND RNumber >= 1 AND RNumber <= 2
Not to sure what is wrong here
You do not need a HAVING clause. You can use a cte function or a subquery. Like this:
;WITH CTE
AS
(
SELECT OITM.ItemCode,OITM.ItemName,ITM1.Price ,
OITM.CardCode,ROW_NUMBER() OVER (ORDER BY OITM.ItemName DESC) AS RNumber
FROM OITM INNER JOIN OCRD ON OCRD.CardCode = OITM.CardCode
INNER JOIN ITM1 ON OITM.ItemCode = ITM1.ItemCode
WHERE OITM.frozenFor='N' AND PriceList=1 AND U_Publish='Y'
)
SELECT
*
FROM
CTE
WHERE
RNumber >= 1 AND RNumber <= 2
Or with a subquery like this:
SELECT
*
FROM
(
SELECT OITM.ItemCode,OITM.ItemName,ITM1.Price ,
OITM.CardCode,ROW_NUMBER() OVER (ORDER BY OITM.ItemName DESC) AS RNumber
FROM OITM INNER JOIN OCRD ON OCRD.CardCode = OITM.CardCode
INNER JOIN ITM1 ON OITM.ItemCode = ITM1.ItemCode
WHERE OITM.frozenFor='N' AND PriceList=1 AND U_Publish='Y'
) AS t
WHERE
t.RNumber >= 1 AND t.RNumber <= 2
You can't use neu defined names in the Where condition, you have to put in the HAVING clause.
SELECT OITM.ItemCode,OITM.ItemName,ITM1.Price ,
OITM.CardCode,
ROW_NUMBER() OVER (ORDER BY OITM.ItemName DESC) AS RNumber
FROM OITM INNER JOIN OCRD ON OCRD.CardCode = OITM.CardCode
INNER JOIN ITM1 ON OITM.ItemCode = ITM1.ItemCode
WHERE OITM.frozenFor='N' AND PriceList=1 AND U_Publish='Y'
HAVING RNumber >= 1 AND RNumb
i use of "codeigniter" and rownum query, i want put WHERE in inside query but have following error. how is it?
A Database Error Occurred Error Number: 1064
You have an error in your SQL syntax; check the manual that
corresponds to your MySQL server version for the right syntax to use
near 'WHERE '*' = '0' ) t, (SELECT #rownum:=0) r' at line 7
SELECT #rownum:=#rownum+1 rownum, t.* FROM ( SELECT * FROM
hotel_submits ORDER BY id desc LIMIT 0, 6 WHERE * = 1 ) t, (SELECT
#rownum:=0) r
Filename: D:\xampp\htdocs\hdr\system\database\DB_driver.php
Line Number: 330
$this->db->query("SELECT #rownum:=#rownum+1 rownum, t.*
FROM (
SELECT *
FROM hasana_you
ORDER BY id desc
LIMIT $offset, $coun_page
WHERE * = 1 //or $id instead 1
) t,
(SELECT #rownum:=0) r");
WHERE always comes before LIMIT and ORDER:
EDITED PER DISCUSSION
SELECT
#rownum:=#rownum+1 rownum,
t.*
FROM (
SELECT
*
FROM
hasana_you
WHERE
column_a = 1 OR
column_b = 1 OR
column_c = 1 OR
column_d = 1
ORDER BY
id desc
LIMIT
$offset, $count_page
) AS t
There are other issues that I see with this query (seems overly complex, may not need the subquery), but without your db structure I could not presume to correct it. However, the stated order of keywords stands as the primary concern.
Check out these tutorial articles on the various aspects of SQL syntax and usage: http://www.tizag.com/sqlTutorial/sqlwhere.php
Try:
$id= 1;
$f= $this->db->query("SELECT GROUP_CONCAT(column_name,
\" like '%$id%' OR \" SEPARATOR '') AS str
FROM information_schema.columns
WHERE table_name='hasana_you'");
$f1= $f->row();
$filter= substr($f1->str,0,-4);
Edited:
$x= $this->db->query("SELECT * FROM (SELECT #rownum:=#rownum+1 rownum, t.*
FROM (SELECT #rownum:=0) r,
(SELECT *
FROM hasana_you
WHERE $filter
ORDER BY id desc
) t) x
ORDER BY id desc
LIMIT $offset, $count_page");
It's hard to know where you want the filter... can also be:
$x= $this->db->query("SELECT * FROM (SELECT #rownum:=#rownum+1 rownum, t.*
FROM (SELECT #rownum:=0) r,
(SELECT *
FROM hasana_you
ORDER BY id desc
) t) x
WHERE $filter
ORDER BY id desc
LIMIT $offset, $count_page");
I have a PHP script displaying a list of players sorted by their "virtual money":
$sth = $db->prepare("
select u.id,
u.first_name,
u.city,
u.avatar,
m.money,
u.login > u.logout as online
from pref_users u, pref_money m where
m.yw=to_char(current_timestamp, 'IYYY-IW') and
u.id=m.id
order by m.money desc
limit 20 offset ?
");
$sth->execute(array($_GET['offset']));
To show a player position in the list I use a PHP variable $pos which is incremented in a loop while printing their names and further data.
I would like to have that position in the SQL statement instead of PHP for various reasons. So I'm trying the following:
$sth = $db->prepare("
select u.id,
row_number() + ? as pos,
u.first_name,
u.city,
u.avatar,
m.money,
u.login > u.logout as online
from pref_users u, pref_money m where
m.yw=to_char(current_timestamp, 'IYYY-IW') and
u.id=m.id
order by m.money desc
limit 20 offset ?
");
$sth->execute(array($_GET['offset'], $_GET['offset']));
But get the ERROR: window function call requires an OVER clause
I'm trying to add over(m.money) but get a syntax error.
I'm probably misunderstanding the Window Functions doc.
Check the user notes on: http://www.postgresql.org/docs/8.4/interactive/functions-window.html
You will need the Over() to contain the same order by clause as the whole query:
$sth = $db->prepare("
select u.id,
row_number() OVER (order by m.money desc) + ? as pos,
u.first_name,
u.city,
u.avatar,
m.money,
u.login > u.logout as online
from pref_users u, pref_money m where
m.yw=to_char(current_timestamp, 'IYYY-IW') and
u.id=m.id
order by m.money desc
limit 20 offset ?
");
$sth->execute(array($_GET['offset'], $_GET['offset']));
You want row_number() OVER (ORDER BY m.money) + ? etc.