【发布时间】:2020-01-27 15:52:11
【问题描述】:
我有一个 PHP 网页,在事务中运行一些 SQL 查询,以写入 SQL Server 2008 R2 数据库。生产服务器使用:
- PHP 5.3 32 位
- ODBC SQL Server 驱动程序 32 位版本 6.01
- IIS 7.5
在这种环境下一切正常。
我必须在新的 Windows Server 2016 服务器上升级到 PHP 7.3 64 位,运行 IIS 10 和更新的 SQL Server ODBC 驱动程序(64 位)。我尝试运行同一页面,但其中一个查询不起作用:
INSERT INTO LIGNELIVRAISON
(ARTICLEID, LCDEID, LIVID, LIGNELIVQTELIV, LIGNELIVDATECREATION, LIGNELIVQTEINITIALE, LIGNELIVMTUNITHT, LIGNELIVMTUNITTVA, LIGNELIVMTUNITTTC, LIGNELIVMTREMISE, LIGNELIVCODELOT, LIGNELIVDATEPEREMPTION)
VALUES
(1573, 44551, 35232, 3, CONVERT(datetime, '27/09/2019 13:48:54'), 3, 50, 4.25, 54.25, 0, '???', CONVERT(date, '31/12/2050'));
错误信息是:
代码 37000:[Microsoft][ODBC SQL Server Driver][SQL Server]'*=' 附近的语法错误。
正如我们所见,这个查询中没有字符“*=”。我尝试了多个版本的 PHP(5 或 7)、多个和更新的 ODBC 驱动程序,但是当我通过 odbc_exec() 函数运行此查询时,我总是得到相同的结果。我尝试使用 PDO 或 sqlsrv 函数,但结果是一样的。
如果我尝试在 SQL Server Management Studio 中复制/粘贴此查询,它可以正常工作。
我认为它可能与 ODBC 驱动程序有关,但我无法安装当前正在生产的同一个驱动程序,因为它在 Windows 2016 上不起作用并且它是一个 32 位驱动程序。我尝试运行 32 位版本的 PHP 7.3 无济于事。
部分PHP代码:
$ms->hdebug();
//$ms->libre('SET IMPLICIT_TRANSACTIONS OFF');
//$ms->libre('BEGIN TRANSACTION');
odbc_autocommit($ms->get_lien(), false);
$id_utilisateur_creation = id_utilisateur_athome($my, $ms);
// On a ajouté un contrôle en amont mais par sécurité, on ajoute un contrôle ici
if ($id_utilisateur_creation === FALSE) {
$id_utilisateur_creation = 1;
}
// 25 = Fournisseur matériel
$id_type_intervenant = 25;
$type_facture = 'F';
// 2 = Location
$id_type_produit = 2;
// 5 = Livrée
$id_etat_commande = 5;
$franco_port = 'N';
$tproduitcode = 'LOCA';
$date = date('d/m/Y');
$date_heure = date('d/m/Y H:i:s');
$montant_remise = 0;
$total_ttc = 0;
$etat_sejour_suivi = 14;
// Pour éviter une erreur lors de l'insertion des lignes de livraison, liées a une procédure stockée
$code_lot_article = '???';
$date_peremption_article = '31/12/2050';
$commentaires = addslashes('Commande créée pour le bon de location n° ' . $_POST['id_location']);
// Récupération des TVA AtHome
$tva_athome = $ms->lire(
'TVAID, TVATAUX * 100',
'TVA',
"AND TVAVISIBLE = 'O'",
"TVATAUX ASC"
);
$mapping_tva = array();
foreach($tva_athome as $tva) {
list($id_tva, $taux_tva) = $tva;
$mapping_tva[$id_tva] = round($taux_tva, 2);
}
// -
// Etape 1: Création de la commande et lignes de commande
$id_commande = $ms->ajouter(
'CDEFRN',
'UTIID, TPRODUITID, FOURNID, ETATCDEID, PATID,
CDEFRNDATE, CDEFRNFRANCOPORT, CDEFRNDATECREATION, TProduitCode, CDEFRNCOMMENTAIRE',
"$id_utilisateur_creation, $id_type_produit, {$_POST['id_fournisseur']}, $id_etat_commande, {$_POST['ipp']},
CONVERT(date, '$date'), '$franco_port', CONVERT(datetime, '$date_heure'), '$tproduitcode', '$commentaires'"
);
$lignes_commande = array();
// Ajout des lignes d'articles
foreach($_POST['articles'] as $id_article) {
if ($_POST['prix'][$id_article] > 0 && $_POST['quantite'][$id_article] > 0) {
$quantite = $_POST['quantite'][$id_article];
$taux_tva = $mapping_tva[$_POST['tva'][$id_article]];
$prix_ht = round($_POST['prix'][$id_article], 2);
// On calcule les arrondis ici pour ne pas avoir de problème d'arrondi dans AtHome à cause des champs de type money
$prix_ttc = round($prix_ht * (1 + ($taux_tva / 100)), 2);
$montant_tva = $prix_ttc - $prix_ht;
$lignes_commande[$id_article] = $ms->ajouter(
'LIGNECDEFRN',
'CDEFRNID, ARTICLEID, LCDEQTECDE, LCDEMTHT, LCDEMTTVA,
LCDEMTTTC, LCDEMTREMISE, LCDEDATECREATION, LCDEQTEINITIALE',
"$id_commande, $id_article, $quantite, $prix_ht, $montant_tva,
$prix_ttc, $montant_remise, CONVERT(datetime, '$date_heure'), $quantite"
);
$total_ttc += $prix_ttc;
}
}
$total_ttc = round($total_ttc, 2);
// Etape 2: Livraison
$id_livraison = $ms->ajouter(
'LIVRAISON',
'CDEFRNID, LIVDATE, LIVDATECREATION',
"$id_commande, CONVERT(date, '$date'), CONVERT(datetime, '$date_heure')"
);
$lignes_livraison = array();
// Ajout des lignes de livraison
foreach($_POST['articles'] as $id_article) {
if ($_POST['prix'][$id_article] > 0 && $_POST['quantite'][$id_article] > 0) {
$quantite = $_POST['quantite'][$id_article];
$taux_tva = $mapping_tva[$_POST['tva'][$id_article]];
$prix_ht = round($_POST['prix'][$id_article], 2);
// On calcule les arrondis ici pour ne pas avoir de problème d'arrondi dans AtHome à cause des champs de type money
$prix_ttc = round($prix_ht * (1 + ($taux_tva / 100)), 2);
$montant_tva = $prix_ttc - $prix_ht;
$lignes_livraison[$id_article] = $ms->ajouter(
'LIGNELIVRAISON',
'ARTICLEID, LCDEID, LIVID, LIGNELIVQTELIV, LIGNELIVDATECREATION,
LIGNELIVQTEINITIALE, LIGNELIVMTUNITHT, LIGNELIVMTUNITTVA, LIGNELIVMTUNITTTC, LIGNELIVMTREMISE,
LIGNELIVCODELOT, LIGNELIVDATEPEREMPTION',
"$id_article, {$lignes_commande[$id_article]}, $id_livraison, $quantite, CONVERT(datetime, '$date_heure'),
$quantite, $prix_ht, $montant_tva, $prix_ttc, $montant_remise,
'$code_lot_article', CONVERT(date, '$date_peremption_article')"
);
}
}
public function ajouter($table,$champs,$valeurs)
{
if(trim($champs)=="")
{
$req="INSERT INTO ".$table." VALUES(".$valeurs.");";
}
else
{
$req="INSERT INTO ".$table." (".$champs.") VALUES(".$valeurs.");";
}
$retour=-1;
if($this->hdebug)
{
$this->log->logguer("INS",$req);
}
if($this->debug)
{
echo "<debug_sql>".$req."</debug_sql>";
}
else
{
if($this->calcul_temps)
{
$_SESSION["Temps_Execution"]->Debut_Compter("MsSQL");
}
//$res = @mssql_query($req,$this->lien) or $this->erreur("insert",$req,0,"");
//$res = odbc_prepare($this->lien, $req);
//$res_ex = odbc_execute($res);
$res = odbc_exec($this->lien, $req);
if (!$res) {
//var_dump($req);
$this->erreur("insert", $req, odbc_error($this->lien), odbc_errormsg($this->lien));
}
$id_retour=@odbc_exec($this->lien,"SELECT @@IDENTITY") or $this->erreur("insert",$req,0,"");
$retour=odbc_result($id_retour, 1);
if($this->calcul_temps)
{
$_SESSION["Temps_Execution"]->Fin_Compter("MsSQL");
}
//$retour=mysql_insert_id($this->lien);
}
//$retour=0;
return $retour;
}
编辑:查询中的 FR 日期时间格式工作正常。我认为问题根本与它无关。
【问题讨论】:
-
您的查询中的两个
CONVERT调用似乎都不适用于 SQL Server 2016。不过我没有答案。 -
CONVERT 函数在我的服务器上运行良好。我有一个以前的 INSERT 查询,它使用它并且工作正常。
-
我们能多看看你的 php 代码吗?
-
我添加了一些 PHP 代码。
-
另外:如果我在发送查询的函数中注释
if (!$res) { //var_dump($req); $this->erreur("insert", $req, odbc_error($this->lien), odbc_errormsg($this->lien)); }部分,它工作得很好......但这不是解决方案,我需要能够检查错误。
标签: php sql-server windows odbc