ZF 2 MS SQL Server error 1934 on update - sql-server-2008

I get an error while atempting to update a row in my table
$adapter = new Zend\Db\Adapter\Adapter([
'driver' => 'Pdo_dblib',
'hostname' => 'SRVSQL',
'database' => 'TDEV',
'username' => 'sa',
'password' => 'xxxx'
]);
$update = $sql->update('F_ARTFOURNISS')
->set([
'AF_RefFourniss' => $fournRef,
'AF_PrixAch' => $fournPxAchat,
'AF_Remise' => $fournRemise,
'AF_CodeBarre' => $fournGenCode
])
->where(['AR_Ref' => $ref]);
try {
$statement = $sql->prepareStatementForSqlObject($update);
$results = $statement->execute();
} catch (Exception $e) {
echo $e->getMessage() . "\n";
}
I get the following error code when i try to execute the code above:
Statement could not be executed (HY000 - 1934 - General SQL Server error: Check messages from the SQL Server [1934] (severity 16) [(null)] - -1 - 16)
I also tried to add some parameters before executing queries:
$adapter->query("SET ANSI_WARNINGS ON");
$adapter->query("SET ANSI_PADDING ON");
$adapter->query("SET ANSI_NULLS ON");
$adapter->query("SET QUOTED_IDENTIFIER ON");
$adapter->query("SET CONCAT_NULL_YIELDS_NULL ON");
This is an example of the query string generated bellow :
UPDATE [F_ARTICLE] SET [AR_Design] = 'azertyuuio', [FA_CodeFamille] = 'J', [AR_PrixAch] = '153.47', [AR_PrixVen] = '145.7965', [AR_Coef] = '0.95', [AR_PoidsNet] = '0', [AR_UnitePoids] = '2' WHERE [AR_Ref] = '801-0198'
When i paste this line into sql server management studio it's working fine. It's not working in my project.
Thanks for your help

After several reserch, i found the solution here: Error while updating Database with mssql_query
So i updated my code to this:
$conn->executeQuery("
SET
ANSI_NULLS,
QUOTED_IDENTIFIER,
CONCAT_NULL_YIELDS_NULL,
ANSI_WARNINGS,
ANSI_PADDING
ON;
");

Related

date/time of last edit to entire wiki

How can I find the date/time of the last edit to my entire wiki? I would like to write this date/time to a text file and then present it as info on one of my wiki pages as described here using the ExternalData extension.
thank you,
russ
Note 1: Error message I'm getting (using ExternalData 2.3) after editing LocalSettings.php
Note 2: The error message I'm getting after upgrading to ExternalData 3.0
Note 3: After replacing {{#get_external_data: with {{#get_db_data: I get this result (using either 2.3 or 3.0):
Note 4: Relevant lines from LocalSettings.php
$wgScriptPath = "/mediawiki-1.35.1";
$wgServer = WebRequest::detectServer();
## Database settings
$wgDBtype = "mysql";
$wgDBserver = "localhost";
$wgDBname = "mywikidbname";
$wgDBuser = "mywikidbuser";
$wgDBpassword = "*********";
# MySQL specific settings
$wgDBprefix = "";
# MySQL table options to use during installation or update
$wgDBTableOptions = "ENGINE=InnoDB, DEFAULT CHARSET=binary";
$wgShellLocale = "C.UTF-8";
# Enabled extensions. Most of the extensions are enabled by adding
# wfLoadExtension( 'ExtensionName' );
# to LocalSettings.php. Check specific extension documentation for more details.
# The following extensions were automatically enabled:
wfLoadExtension( 'ConfirmEdit' );
wfLoadExtension( 'PdfHandler' );
wfLoadExtension( 'SpamBlacklist' );
wfLoadExtension( 'TitleBlacklist' );
#wfLoadExtension( 'VisualEditor' );
wfLoadExtension( 'WikiEditor' );
wfLoadExtension( 'MathJax' );
wfLoadExtension( 'ImageMap' );
wfLoadExtension( 'Quiz' );
wfLoadExtension( 'TextScroller' );
wfLoadExtension( 'ExternalData' );
$edgCacheExpireTime=10;
$edgFilePath['inject'] = '/home/rwp/shares/share_wiki/rwp_external_data.txt';
$wgExternalDataSources['MW DB'] = [
'type' => 'mysql',
'server' => $wgDBserver,
'user' => $wgDBuser,
'password' => $wgDBpassword,
'name' => $wgDBname,
'prepared' => [
'last revision' => 'SELECT rev_timestamp AS last FROM revision ORDER BY rev_timestamp DESC LIMIT 1;'
]
];
Using External Data, you can insert the time of the last revision to the wiki without a file. Add to LocalSettings.php:
$wgExternalDataSources['MW DB'] = [
'type' => 'mysql',
'server' => $wgDBserver,
'user' => $wgDBuser,
'password' => $wgDBpassword,
'name' => $wgDBname,
'prepared' => [
'last revision' => 'SELECT MAX(rev_timestamp) AS last FROM revision;'
]
];
Then get the required time with {{#get_external_data: db = MW DB | query = last revision | data = last = last}}{{#time: r | {{#external_value: last}} }} .
If you want to use a file, create it with the following bash script:
mysql -h ($wgDBserver) -u ($wgDBuser) -p($wgDBpassword) ($wgDBname) -e "SELECT MAX(rev_timestamp) AS last FROM revision;" > last_revision.txt

Symfony3 : How to do a massive import from a CSV file as fast as possible?

I have a .csv file with more than 690 000 rows.
I found a solution to import data that works very well but it's a little bit slow... (around 100 records every 3 seconds = 63 hours !!).
How can I improve my code to make it faster ?
I do the import via a console command.
Also, I would like to import only prescribers that aren't already in database (to save time). To complicate things, no field is really unique (except for id).
Two prescribers can have the same lastname, firstname, live in the same city and have the same RPPS and professional codes. But, it's the combination of these 6 fields which makes them unique !
That's why I check on every field before create a new one.
<?php
namespace AppBundle\Command;
use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Helper\ProgressBar;
use AppBundle\Entity\Prescriber;
class PrescribersImportCommand extends ContainerAwareCommand
{
protected function configure()
{
$this
// the name of the command (the part after "bin/console")
->setName('import:prescribers')
->setDescription('Import prescribers from .csv file')
;
}
protected function execute(InputInterface $input, OutputInterface $output)
{
// Show when the script is launched
$now = new \DateTime();
$output->writeln('<comment>Start : ' . $now->format('d-m-Y G:i:s') . ' ---</comment>');
// Import CSV on DB via Doctrine ORM
$this->import($input, $output);
// Show when the script is over
$now = new \DateTime();
$output->writeln('<comment>End : ' . $now->format('d-m-Y G:i:s') . ' ---</comment>');
}
protected function import(InputInterface $input, OutputInterface $output)
{
$em = $this->getContainer()->get('doctrine')->getManager();
// Turning off doctrine default logs queries for saving memory
$em->getConnection()->getConfiguration()->setSQLLogger(null);
// Get php array of data from CSV
$data = $this->getData();
// Start progress
$size = count($data);
$progress = new ProgressBar($output, $size);
$progress->start();
// Processing on each row of data
$batchSize = 100; # frequency for persisting the data
$i = 1; # current index of records
foreach($data as $row) {
$p = $em->getRepository('AppBundle:Prescriber')->findOneBy(array(
'rpps' => $row['rpps'],
'lastname' => $row['nom'],
'firstname' => $row['prenom'],
'profCode' => $row['code_prof'],
'postalCode' => $row['code_postal'],
'city' => $row['ville'],
));
# If the prescriber doest not exist we create one
if(!is_object($p)){
$p = new Prescriber();
$p->setRpps($row['rpps']);
$p->setLastname($row['nom']);
$p->setFirstname($row['prenom']);
$p->setProfCode($row['code_prof']);
$p->setPostalCode($row['code_postal']);
$p->setCity($row['ville']);
$em->persist($p);
}
# flush each 100 prescribers persisted
if (($i % $batchSize) === 0) {
$em->flush();
$em->clear(); // Detaches all objects from Doctrine!
// Advancing for progress display on console
$progress->advance($batchSize);
$progress->display();
}
$i++;
}
// Flushing and clear data on queue
$em->flush();
$em->clear();
// Ending the progress bar process
$progress->finish();
}
protected function getData()
{
// Getting the CSV from filesystem
$fileName = 'web/docs/prescripteurs.csv';
// Using service for converting CSV to PHP Array
$converter = $this->getContainer()->get('app.csvtoarray_converter');
$data = $converter->convert($fileName);
return $data;
}
}
EDIT
According to #Jake N answer, here is the final code.
It's very very faster ! 10 minutes to import 653 727 / 693 230 rows (39 503 duplicate items!)
1) Add two columns in my table : created_at and updated_at
2) Add a single index of type UNIQUE on every column of my table (except id and dates) to prevent duplicate items with phpMyAdmin.
3) Add ON DUPLICATE KEY UPDATE in my query, to update just the updated_at column.
foreach($data as $row) {
$sql = "INSERT INTO prescripteurs (rpps, nom, prenom, code_prof, code_postal, ville)
VALUES(:rpps, :nom, :prenom, :codeprof, :cp, :ville)
ON DUPLICATE KEY UPDATE updated_at = NOW()";
$stmt = $em->getConnection()->prepare($sql);
$r = $stmt->execute(array(
'rpps' => $row['rpps'],
'nom' => $row['nom'],
'prenom' => $row['prenom'],
'codeprof' => $row['code_prof'],
'cp' => $row['code_postal'],
'ville' => $row['ville'],
));
if (!$r) {
$progress->clear();
$output->writeln('<comment>An error occured.</comment>');
$progress->display();
} elseif (($i % $batchSize) === 0) {
$progress->advance($batchSize);
$progress->display();
}
$i++;
}
// Ending the progress bar process
$progress->finish();
1. Don't use Doctrine
Try to not use Doctrine if you can, it eats memory and as you have found is slow. Try and use just raw SQL for the import with simple INSERT statements:
$sql = <<<SQL
INSERT INTO `category` (`label`, `code`, `is_hidden`) VALUES ('Hello', 'World', '1');
SQL;
$stmt = $this->getDoctrine()->getManager()->getConnection()->prepare($sql);
$stmt->execute();
Or you can prepare the statement with values:
$sql = <<<SQL
INSERT INTO `category` (`label`, `code`, `is_hidden`) VALUES (:label, :code, :hidden);
SQL;
$stmt = $this->getDoctrine()->getManager()->getConnection()->prepare($sql);
$stmt->execute(['label' => 'Hello', 'code' => 'World', 'hidden' => 1);
Untested code, but it should get you started as this is how I have done it before.
2. Index
Also, for your checks, have you got an index on all those fields? So that the lookup is as quick as possible.

UTF-8 Bad Encoding when Using ZF2 dbAdapter for mySQL for Update

I am getting the Exception when I attempt to update the record with "tableGateway" object:
Zend\Db\Adapter\Exception\InvalidQueryException
Statement could not be executed
(HY000 - 1300 - Invalid utf8 character string: 'C`\xC3`\xB3`digo')
I have the following table structure with data in mySQL:
CREATE TABLE `clientes` (
`Código` int,
`Nome` varchar(50),
`Descricao` varchar(150)
....
);
INSERT INTO `clientes` (`Código`, `Nome`, `Descricao`)
VALUES (1, 'Test Nome', 'Test Descricao');
The database encoding is 'latin1', but the database configuration is as shown:
'mycnn' => array(
'driver' => 'pdo',
'dsn' => 'mysql:dbname={$mydb};host={$myhost}',
'username' => '{$myuser}',
'password' => '{$mypassword}',
'driver_options' => array(
PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES \'UTF8\''
),
)
As you can see the above scenario, I have setup the driver for "UTF-8", the column name "Código" has a special character and renaming this column is not an option.
The syntax that I am using for updating in the model is:
$set = array("Nome" => "Edited Test");
$where = array("Código" => 1);
$this->tableGateway->update($set, $where);
After that, the ZF is parsing the SQL throwing the Exception:
UPDATE "clientes" SET "Nome" = 'Edited Test' WHERE "C`\xC3`\xB3`digo" = 1
I have also removed the UTF-8 option, since the catalog is "latin1_swedish_ci" without success.
I would appreciate anyone who gives me a hint how to face this issue.
Thanks in advance.
Make sure your database encoding type is UTF-8.
'driver_options' => array(
PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES \'UTF8\''
),
Make sure fields have utf8_general_ci.
In your layout phtml head has
<meta charset='utf-8'>
Updated
As you said you are not able to change encoding to utf-8 so use one of the following commands using driver_options
'SET NAMES \'latin1\'' or 'SET CHARACTER SET \'latin1\''
For more details check out the doc please!
When problem with column name which has latin1 characters
Just pass the condition as string not an array as the second argument into TableGateway's update() method. But you must set this 'SET NAMES \'UTF8\'' in your driver_options.
$id = 1;
$where = "Código = {$id}";
// Or use this way
$where = "Código = 1";
$this->tableGateway->update($set, $where);

Tried to bind parameter number 0. SQL Server supports a maximum of 2100 parameters

I'm currently using a PDO class that works on MySQL perfectly. But when it comes to MSSQL , I get an error when I try to insert data via the bindValue() function.
I'm using this method for data binding:
bindValue(":param",$value)
Step 1 - Create an array for the table fields in the query
$counter = 0;
foreach($fields as $cols)
{
$fieldBind[$counter] = ":".$cols;
$new_f = $new_f ."". $cols;
$counter ++;
if($counter!=count($fields))
{
$new_f = $new_f.",";
}
}
output : (
[0] => :field1
[1] => :field2
[2] => :field3
)
Step 2 - Create an array for the data of the fields in the query
$counter2 = 0;
foreach($data as $cols)
{
$dataBind[$counter2] = $cols;
$new_d = $new_d."'".$cols."'";
$counter2 ++;
if($counter2!=count($data))
{
$new_d = $new_d.",";
}
}
output : ( [0] => value1 [1] => value2 [2] => value3 )
Step 3 - Prepare the query via the query function
parent::query("INSERT INTO $table($new_f) VALUES($new_d)");
Step 4 - Bind the Parameters and Values
for($i=0;$i<count($data);$i++){
parent::bind($fieldBind[$i],$dataBind[$i]);
}
The query looks like this:
INSERT INTO table(field1,field2,field3) values(':value1',':value2',':value3')
Step 5 - Execute the Query
try {
parent::execute();
return parent::rowCount();
}
catch(PDOException $e) {
echo $e->getMessage();
}
This method works perfectly on MySQL, but when I try to execute this on SQL Server, I get this error:
SQLSTATE[IMSSP]: Tried to bind parameter number 0. SQL Server supports a maximum of 2100 parameters.
Try removing the apostrophe ''
from :
INSERT INTO table(field1,field2,field3) values(':value1',':value2',':value3')
to the following:
INSERT INTO table(field1,field2,field3) values(:value1,:value2,:value3)

Using PDO to insert variables into SELECT clause?

I am attempting to get the distance from a user to each venue stored in a MySQL database, using the spherical law of cosines. The user inputs their location, and the following query is executed.
$data = array(':lat' => $lat, ':lon' => $lon);
$qry = "SELECT ACOS(SIN(v.Latitude) * SIN(:lat) + COS(v.Latitude) * COS(:lat) * COS(:lon - v.Longitude)) * 3963 AS distance FROM Venue v";
$stmt = $pdo->prepare($qry);
$stmt->execute($data);
$rows = $stmt->fetchAll();
The problem is, I get the following error.
PHP Fatal error: Uncaught exception 'PDOException' with message 'SQLSTATE[HY093]: Invalid parameter number'
When I remove the variables (:lat and :lon) from the SELECT clause, it works just fine. Other variables further on in the statement (not shown here) work just fine, it is only the variables in the SELECT clause that cause an issue. Is this inability to use PDO variables within SELECT clauses a limitation of PDO, or is there a way around this issue?
I am using PHP 5.4.15, and my PDO options are as follows.
$options = array(PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8', // UTF-8 to prevent issue sending special characters with JSON
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, // fire exceptions for errors (turn this off for release)
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, // only return results indexed by column name
PDO::ATTR_EMULATE_PREPARES => false // actually prepare statements, not pseudo-prepare ( http://stackoverflow.com/questions/10113562/pdo-mysql-use-pdoattr-emulate-prepares-or-not )
);
$data = array($lat, $lat, $lon);
$qry = "SELECT ACOS(SIN(v.Latitude) * SIN(?) + COS(v.Latitude) * COS(?) * COS(? - v.Longitude)) * 3963 AS distance FROM Venue v";
$stmt = $pdo->prepare($qry);
$stmt->execute($data);
$rows = $stmt->fetchAll();