PHP 中的 Oracle SQL 请求不返回任何内容,但在 SQL Developer 中有效
Posted
技术标签:
【中文标题】PHP 中的 Oracle SQL 请求不返回任何内容,但在 SQL Developer 中有效【英文标题】:Oracle SQL request in PHP not returning anything but works in SQL Developer 【发布时间】:2021-06-28 05:11:30 【问题描述】:我遇到了一个问题,我有一个请求可以在 SQL Developer
或 VsCode
中使用 oracle DB
附加组件,但在 php 代码中,它返回 0 行。 PHP
版本太旧了,我对此无能为力,5.4.6,OracleDB
是 11g (11.2.0.3.0
)。
这是请求:
$sql = "SELECT
PATIENT_SOIGNE.NOM,
PATIENT_SOIGNE.PATRONYME AS NOM_NAISSANCE,
PATIENT_SOIGNE.PRENOM,
to_date(PATIENT_SOIGNE.DATENAIS,'YYYYMMDD') AS DDN,
decode(PATIENT_SOIGNE.SEXE,'F','Femme','M','Homme','Inconnu') AS SEXE,
PATIENT_SOIGNE.NIP,
S_ACTE_MED.CODEP1 || ' - ' || ( S_ACTE_MED.LIBELLE ) AS ACTE,
OPERATEUR.NOM AS NOM_OPERATEUR,
OPERATEUR.PRENOM AS PRENOM_OPERATEUR
FROM
PENSOINS.ACTE_RDV,
PENSOINS.RDV_STATUT RDV_STATUT,
PENSOINS.ACTE_RDV_GRP,
PENSOINS.S_ACTE_M S_ACTE_MED,
PENSOINS.EJ_PERSO OPERATEUR,
(
SELECT RESSOURCE_OPERATEUR.*, ACTE_RDV_RESA.NIACTERDV
FROM
PENSOINS.DXP_RESSOURCE RESSOURCE_OPERATEUR, PENSOINS.ACTE_RDV_RESA ACTE_RDV_RESA
WHERE
RESSOURCE_OPERATEUR.ID_RESSOURCE=ACTE_RDV_RESA.REF_RESSOURCE
AND
RESSOURCE_OPERATEUR.REF_TYPE_RESSOURCE=1
) TD_RESSOURCE_OPERATEUR,
PENSOINS.EJ_SRV RDV_SRV,
PENSOINS.VENUE,
(
SELECT A.NIACTERDV, A.NIVENUE, TD.NISEJMOUV, V.NIPATIENT, nvl(TD.NISEJOUR, V.NISEJOUR) as NISEJOUR, V.NISERVICE
FROM PENSOINS.ACTE_RDV A,
PENSOINS.VENUE V,
(
SELECT L.NIACTERDV, L.NIVENUE, DER.DATE_DER_MAJ, L.NISEJMOUV, M.NISEJOUR
FROM PENSOINS.LIEN_RDV_MVT L,
PENSOINS.MOUVEMEN M,
(
SELECT A.NIACTERDV, A.NIVENUE, max(nvl(L.DATE_MODIF, L.DATE_CREA)) DATE_DER_MAJ
FROM PENSOINS.ACTE_RDV A,
PENSOINS.LIEN_RDV_MVT L
WHERE A.NIACTERDV = L.NIACTERDV
AND L.RETRAIT = 'F'
GROUP BY A.NIVENUE,A.NIACTERDV
) DER
WHERE L.NISEJMOUV = M.NISEJMOUV
AND DER.NIACTERDV = L.NIACTERDV
AND DER.NIVENUE = L.NIVENUE
AND DER.DATE_DER_MAJ = nvl(L.DATE_MODIF, L.DATE_CREA)
AND L.RETRAIT = 'F'
) TD
WHERE A.NIVENUE(+) = V.NIVENUE
AND TD.NIACTERDV(+) = A.NIACTERDV
) TD_VENUE,
PENSOINS.PATIENT PATIENT_SOIGNE
WHERE
( PENSOINS.ACTE_RDV.STATUTRDV=RDV_STATUT.NI(+) )
AND ( PENSOINS.ACTE_RDV_GRP.NIACTERDV=PENSOINS.ACTE_RDV.NIACTERDV )
AND ( S_ACTE_MED.NIACTE=PENSOINS.ACTE_RDV_GRP.NIACTE and S_ACTE_MED.NISERVICE=PENSOINS.ACTE_RDV_GRP.NISERVICE )
AND ( OPERATEUR.NIUTILISAT(+)=TD_RESSOURCE_OPERATEUR.ID_DXCARE )
AND ( TD_RESSOURCE_OPERATEUR.NIACTERDV(+)=PENSOINS.ACTE_RDV.NIACTERDV )
AND ( PENSOINS.ACTE_RDV.NISERVICE=RDV_SRV.NISERVICE(+) )
AND ( PENSOINS.VENUE.NIVENUE=TD_VENUE.NIVENUE )
AND ( TD_VENUE.NIACTERDV=PENSOINS.ACTE_RDV.NIACTERDV(+) )
AND ( PATIENT_SOIGNE.NIPATIENT(+)=PENSOINS.VENUE.NIPATIENT )
AND RDV_STATUT.CODE|| ' - ' ||RDV_STATUT.LIBELLE IN ( 'R - Attribué','M - Modifié' )
AND RDV_SRV.CODE||' - '||RDV_SRV.NOM IN ( '07 - Diététique','08 - Endocrinologie','18 - Oncologie','19 - Ophtalmologie','24 - Pneumologie','30 - Rhumatologie','34 - Orthophonie','40 - Consultations externes','42 - Stomatologie','43 - HOPITAL DE JOUR MEDECINE','44 - Hématologie','20 - ORL','CE 02 - Anesthésie','CE 03 - Cardiologie','CE 04 - Chirurgie Orthopédique','CE 06 - Chirurgie Urologique','CE 07 - Chirurgie Viscérale','CE 08 - Hépato-gastro-entérologie','CE 09 - Chirurgie Plastique','CE 10 - Gériatrie','CE 11 - Gynécologie-Obstétrique','CE 12 - Médecine interne','CE 14 - Pédiatrie','CE 15 - Tabacologie','CE 16 - Chirurgie Vasculaire','16 - Néphrologie' )
AND substr(PENSOINS.ACTE_RDV.HORAIRE, 1, 8) = '".$date_next."'
GROUP BY
PATIENT_SOIGNE.NOM,
PATIENT_SOIGNE.PATRONYME,
PATIENT_SOIGNE.PRENOM,
to_date(PATIENT_SOIGNE.DATENAIS,'YYYYMMDD'),
decode(PATIENT_SOIGNE.SEXE,'F','Femme','M','Homme','Inconnu'),
PATIENT_SOIGNE.NIP,
S_ACTE_MED.CODEP1 || ' - ' || ( S_ACTE_MED.LIBELLE ),
OPERATEUR.NOM,
OPERATEUR.PRENOM";
以及使用它的代码:
$date_next = date_next_day();
$db_o = connexion_oracle_dxcare();
$parsed = oci_parse($db_o, $sql);
$ru=oci_execute($parsed);
if (!$ru) //doesn't show anything
$e = oci_error($parsed);
print htmlentities($e['message']);
print "\n<pre>\n";
print htmlentities($e['sqltext']);
printf("\n%".($e['offset']+1)."s", "^");
print "\n</pre>\n";
$num_rows = oci_fetch_all($parsed, $res); //returns 0 rows
var_dump($res); //show me all the column names but no datas inside
日期格式很好,我的函数返回这种格式 'YYYYMMDD
' 有效。
var 转储显示:
array(9) ["NOM"]=> array(0) ["NOM_NAISSANCE"]=> array(0) ["PRENOM"]=> array(0) ["DDN"]=> array(0) ["SEXE"]=> array(0) ["NIP"]=> array(0) ["ACTE"]=> array(0) ["NOM_OPERATEUR"]=> array(0) ["PRENOM_OPERATEUR"]=> array(0)
我肯定错过了一些东西,但我找不到它。有什么想法吗?
编辑:
所以我测试了问题是否出在口音上,但是这个请求:
SELECT PENSOINS.EJ_SRV.NOM from PENSOINS.EJ_SRV WHERE PENSOINS.EJ_SRV.NOM LIKE 'Dié%'
工作正常(即使它随后在浏览器中显示为 é)。
我改变了这部分:
AND substr(PENSOINS.ACTE_RDV.HORAIRE, 1, 8) = '".$date_next."'
GROUP BY
PATIENT_SOIGNE.NOM,
PATIENT_SOIGNE.PATRONYME,
PATIENT_SOIGNE.PRENOM,
to_date(PATIENT_SOIGNE.DATENAIS,'YYYYMMDD'),
多次,使用了一些 to_char、trunc、to_date 但没有任何效果。
关于日期,我能够发表以下声明:
SELECT PENSOINS.ACTE_RDV.HORAIRE from PENSOINS.ACTE_RDV WHERE substr(PENSOINS.ACTE_RDV.HORAIRE, 1, 8) = :date_test_bv
工作。这里:date_test_bv
是一个字符串的绑定变量,比如20140415
所以现在我回来了
AND RDV_SRV.CODE||' - '||RDV_SRV.NOM IN ( '07 - Diététique','08 - Endocrinologie','18 - Oncologie','19 - Ophtalmologie','24 - Pneumologie','30 - Rhumatologie','34 - Orthophonie','40 - Consultations externes','42 - Stomatologie','43 - HOPITAL DE JOUR MEDECINE','44 - Hématologie','20 - ORL','CE 02 - Anesthésie','CE 03 - Cardiologie','CE 04 - Chirurgie Orthopédique','CE 06 - Chirurgie Urologique','CE 07 - Chirurgie Viscérale','CE 08 - Hépato-gastro-entérologie','CE 09 - Chirurgie Plastique','CE 10 - Gériatrie','CE 11 - Gynécologie-Obstétrique','CE 12 - Médecine interne','CE 14 - Pédiatrie','CE 15 - Tabacologie','CE 16 - Chirurgie Vasculaire','16 - Néphrologie' )
AND substr(PENSOINS.ACTE_RDV.HORAIRE, 1, 8) = :date_bv
GROUP BY
PATIENT_SOIGNE.NOM,
PATIENT_SOIGNE.PATRONYME,
PATIENT_SOIGNE.PRENOM,
to_date(PATIENT_SOIGNE.DATENAIS,'YYYYMMDD'),
decode(PATIENT_SOIGNE.SEXE,'F','Femme','M','Homme','Inconnu'),
PATIENT_SOIGNE.NIP,
S_ACTE_MED.CODEP1 || ' - ' || ( S_ACTE_MED.LIBELLE ),
OPERATEUR.NOM,
OPERATEUR.PRENOM
知道绑定的字符串日期会产生成功的结果,并且使用重音符号不是问题。 我有 0 条错误消息,也不是来自 PHP 或 Oracle,只是像我之前显示的 var 转储一样的空行。 那时我真的不明白问题出在哪里。
【问题讨论】:
使用像AND substr(PENSOINS.ACTE_RDV.HORAIRE, 1, 8) = '".$date_next."'
这样的连接是一个性能问题和一个SQL注入安全问题。您必须使用绑定变量。
首先添加一些错误检查。添加error_reporting(E_ALL); ini_set('display_errors', 'On');
并检查来自OCI 调用的适当返回值,请参阅文档php.net/manual/en/function.oci-error.php
【参考方案1】:
隐式日期转换负责大多数在不同客户端中以不同方式工作的查询。日期格式默认为在 system 级别设置的 NLS_DATE_FORMAT
值,但许多客户端会通过在 session 级别设置参数来覆盖该值。
具体来说,这两个表达式可能有问题:
substr(PENSOINS.ACTE_RDV.HORAIRE, 1, 8) = '".$date_next."
...
to_date(PATIENT_SOIGNE.DATENAIS,'YYYYMMDD')
许多人通过强制所有客户端更改其设置来解决这些问题,但更好的永久解决方案始终是指定所需的格式,或者完全避免日期转换。假设这两列是日期值,将表达式重写为这样会更安全:
substr(to_char(PENSOINS.ACTE_RDV.HORAIRE, 1, 8), 'YYYYMMDD') = '".$date_next."'
...
trunc(PATIENT_SOIGNE.DATENAIS)
(我不确定 PHP 是如何工作的,可能有更好的方法将 $date_next
作为日期而不是字符串传递。)
另一个疯狂的猜测是非 ASCII 字符串在某处引起了问题:
RDV_SRV.CODE||' - '||RDV_SRV.NOM IN ( '07 - Diététique', ...
查看select sql_fulltext from gv$sql where lower(sql_fulltext) like '%07 - Di%;
的输出以确保查询正确传递给Oracle。如果某些文件或进程不支持非 ASCII 字符,那么您可能需要像这样存储 Unicode 字符串:
RDV_SRV.CODE||' - '||RDV_SRV.NOM IN ( '07 - Di'||unistr('\00E9')|'t'||unistr('\00E9')||'tique', ...
【讨论】:
如果字符集有问题,连接时设置字符集。见php.net/manual/en/function.oci-connect.php$conn = oci_connect('hr', 'welcome', 'localhost/XE', 'AL32UTF8');
中的示例3
您好,我在进行了更多测试后编辑了我的问题。似乎编码或日期都不是这里的问题。 (除非我当然错过了什么!)以上是关于PHP 中的 Oracle SQL 请求不返回任何内容,但在 SQL Developer 中有效的主要内容,如果未能解决你的问题,请参考以下文章