Warning: Cannot use a scalar value as an array in /home/admin/public_html/forum/include/fm.class.php on line 757

Warning: Invalid argument supplied for foreach() in /home/admin/public_html/forum/include/fm.class.php on line 770
Форумы портала PHP.SU :: Версия для печати :: PDO запрос
Форумы портала PHP.SU » » Вопросы новичков » PDO запрос

Страниц (1): [1]
 

1. imper - 01 Октября, 2014 - 12:45:12 - перейти к сообщению
Добрый день.

щас приведу пример что бы был понятен этот бред, у меня в базе 11 записей, одна запись уже "добавлена" , вообщем остаётся 10 записей которые должны мне вывестись при загрузке страницы и ничего не должно подгружаться когда я прокручиваю страницу вниз (аякс подзагрузка при прокрутке страницы стоит)
но почему то у меня подгружается эта 11 запись, когда LIMIT 10,20

проверяю sql запрос в phpmyadmin'е всё нормально выводит

если обрамлять в phpmyadmin'е NOT IN ('77,101,....') то ведёт себя так же как и запрос в php скрипте, в чём же проблема ? О_о

PHP:
скопировать код в буфер обмена
  1.   $id_user = intval($_SESSION['id']);
  2.   $cur = intval($_POST['cursor']);
  3.   $get_data_sel_msg = $_POST['sel'];
  4.   $tems = strval($_SESSION['connect_tems']);//в сессии хранится строка вида 77,23,11,...
  5.  



есть запрос
CODE (SQL):
скопировать код в буфер обмена
  1.  
  2. SELECT chat_tema.id,chat_tema.id_user,chat_tema.tema, chat_tema.count, chat_tema.date, chat_tema.img,profile_user.name_user, profile_user.family_user
  3.         FROM  friends_iv,chat_tema,profile_user
  4.         WHERE chat_tema.id NOT IN(:tems) AND (friends_iv.id_user_ot = :id_us1 OR friends_iv.id_user_pol = :id_us2) AND friends_iv.readed = 1
  5.         AND ( (friends_iv.id_user_ot = :id_us3 AND friends_iv.id_user_pol =  chat_tema.id_user) OR (friends_iv.id_user_ot =  chat_tema.id_user AND friends_iv.id_user_pol = :id_us4 ) )
  6.         AND profile_user.id = chat_tema.id_user
  7.         ORDER BY chat_tema.id DESC LIMIT :cursor,20
  8.  


вообщем обратите внимание на NOT IN (:tems)

вот сдесь я вставляю все данные

PHP:
скопировать код в буфер обмена
  1. $sth = $db->pdo_obj->prepare($sql_osn);
  2. $sth->bindParam(':id_us1', $id_user , PDO::PARAM_INT);
  3.  
  4. $sth->bindParam(':tems'  , $tems    , PDO::PARAM_STR);
  5. $sth->bindParam(':id_us2', $id_user , PDO::PARAM_INT);
  6. $sth->bindParam(':id_us3', $id_user , PDO::PARAM_INT);
  7. $sth->bindParam(':id_us4', $id_user , PDO::PARAM_INT);
  8. $sth->bindParam(':cursor', $cur    , PDO::PARAM_INT);
  9.        
  10. $sth->execute();
  11. echo json_encode($sth->fetchAll());//отправляю клиенту
  12.  


вообщем вставляю я всё правильно всё работает просто не пойму почему мне эта 11 запись продгружается
2. esterio - 01 Октября, 2014 - 12:55:59 - перейти к сообщению
PDO не может подставить в prepare в оператор IN строку
нужно делать
CODE (SQL):
скопировать код в буфер обмена
  1.  NOT IN(:tems0, :tems1 ...)

а в PHP
PHP:
скопировать код в буфер обмена
  1. $sth->bindParam(':tems0'  , $tems[0]    , PDO::PARAM_STR);
  2. $sth->bindParam(':tems1'  , $tems[1]    , PDO::PARAM_STR);
  3. // ...

ну и вместо строкы держать массив
PHP:
скопировать код в буфер обмена
  1. $_SESSION['connect_tems'] = array(77, 23, ...)
3. Мелкий - 01 Октября, 2014 - 13:05:20 - перейти к сообщению
imper пишет:
$sth->bindParam(':id_us1', $id_user , PDO::PARAM_INT); 
$sth->bindParam(':id_us2', $id_user , PDO::PARAM_INT);
$sth->bindParam(':id_us3', $id_user , PDO::PARAM_INT);
$sth->bindParam(':id_us4', $id_user , PDO::PARAM_INT);

Это не имеет смысла, PDO умеет один параметр корректно подставлять в запросе несколько раз.
Т.е. можно спокойно писать where user_id_from=:id_us or user_id_to=:id_us и биндить только id_us

По теме - да, IN препарированным запросом делать неудобно.
Если делать field in (:var) и биндить значения через запятую, то и получится field in ('значения через запятую'), что эквивалентно field = 'значения через запятую'
Т.е. смысла не имеет.
Надо делать field in (:var1, :var2, ...) и биндить отдельно значения.
4. imper - 01 Октября, 2014 - 13:08:55 - перейти к сообщению
Ну теперь понятно, просто интересно почему он не может в NOT IN обычную строку впихнуть?

я просто вместо параметра :tems вставил в запрос переменную напрямую

CODE (SQL):
скопировать код в буфер обмена
  1. SELECT chat_tema.id,chat_tema.id_user,chat_tema.tema, chat_tema.count, chat_tema.date, chat_tema.img,profile_user.name_user, profile_user.family_user
  2.         FROM  friends_iv,chat_tema,profile_user
  3.         WHERE chat_tema.id NOT IN($tems) AND (friends_iv.id_user_ot = :id_us1 OR friends_iv.id_user_pol = :id_us2) AND friends_iv.readed = 1
  4.         AND ( (friends_iv.id_user_ot = :id_us3 AND friends_iv.id_user_pol =  chat_tema.id_user) OR (friends_iv.id_user_ot =  chat_tema.id_user AND friends_iv.id_user_pol = :id_us4 ) )
  5.         AND profile_user.id = chat_tema.id_user
  6.         ORDER BY chat_tema.id DESC LIMIT :cursor,20
5. esterio - 01 Октября, 2014 - 13:36:04 - перейти к сообщению
для ответа нужно знать как оно работает, а эт ен 5 минут. думаю вам стоит поискать в гугле
6. Мелкий - 01 Октября, 2014 - 13:46:41 - перейти к сообщению
imper пишет:
просто интересно почему он не может в NOT IN обычную строку впихнуть?

Именно что строку и вставляет. А вам-то не нужна строка, вам нужны пачка параметров с разделителем-запятой. А получается один элемент - строка.
7. teddy - 01 Октября, 2014 - 18:22:24 - перейти к сообщению
А все таки вопрос можно решить и без отдельного биндинга.

Идея в том, что бы подставлять в запрос не именованные параметры, а вопросики, которые PDO скушает и не подавится.

Для начала нужно понимать, что для того что бы использовать такух схему, вам нужен отдельный массив данных с теми значениями, которые должны быть подставлены в IN, и отдельный массив данных, значения из которого будут использоваться в WHERE, AND и т.п
Почему? Должно быть ясно по коду.

PHP:
скопировать код в буфер обмена
  1. $params = array(1,2,3);//массив, в котором лежает данные для IN
  2. $data = array(1);//массив, который содержит данные для условий в запросе
  3.  
  4. $inParams = rtrim(str_repeat('?,', count($params)), ',');//генерим вопросики для IN
  5. $allParams = array_merge($data, $params);//соединяем данные для условий и IN
  6.  
  7. $stmt = $dbh->prepare('SELECT `some`,`columns` FROM `table` WHERE `col` > ? AND `id` IN('.$inParams.')');
  8. $stmt->execute($allParams);


Порядок передаваемых значений в array_merge должен быть именно таким.
8. esterio - 01 Октября, 2014 - 18:26:23 - перейти к сообщению
ну тогда теряеться возможность именных плейсхолдеров
9. teddy - 01 Октября, 2014 - 18:32:47 - перейти к сообщению
esterio
Ну и пусть Улыбка Не вижу проблем... В конечном счете это никак не влияет на выполнение запроса
10. Мелкий - 01 Октября, 2014 - 18:36:05 - перейти к сообщению
esterio пишет:
ну тогда теряеться возможность именных плейсхолдеров

Не теряется.
Ничто не мешает с совершенно тем же результатом сформировать in (:mydata1, :mydata2, ..) и скормить execute ассоциативный массив с mydata1=>$data1, mydata2=>$data2
Это одно и то же.

Проблема в том, что это именно биндинг отдельных элементов и есть. Вопросиками или именованными параметрами - без разницы.
11. teddy - 01 Октября, 2014 - 18:53:45 - перейти к сообщению
Мелкий
В принципе да, отдельный биндинг все равно так или иначе должен быть.
Этот способ лишь попытка уйти от явного и неоднократного вызова метода bindParam.

 

Powered by ExBB FM 1.0 RC1