Converting Date column to ODBC canonical format in SQL Server 2005 - php

I'm dealing with the issue of converting a Date column to an ODBC canonical format in my Microsoft SQL Server 2008.
I have the following SQL query in php:
$sql_query = "UPDATE [$connectionInfo[Database]].[dbo].[log_record] SET [lock]='0' WHERE CONVERT [Date] = '".json_encode($value['Date']['date'])."'
Basically, the part '".json_encode($value['Date']['date'])."' works and is printed as '"2017-06-01 00:00:00"'. But it's the [Date] column that's the problem. How can I compare them? It generates the following error:
error: Conversion failed when converting date and/or time from
character string. query: UPDATE [dba_sql].[dbo].[log_record] SET
[lock]='0' WHERE [Date] = '"2017-06-01 00:00:00"'
I attempted the following, but in vain:
$sql_query = "UPDATE [$connectionInfo[Database]].[dbo].[log_record] SET [lock]='0' WHERE CONVERT CONVERT(varchar, Date, 120) = '".json_encode($value['Date']['date'])."'

Get rid of the double quotes, and remove the convert hanging in your code. There is no need to convert the date in your table to a character type for your comparison.
The following is valid: select convert(date,'2017-06-01 00:00:00')
This is not: select convert(date,'"2017-06-01 00:00:00"')
rextester demo: http://rextester.com/NUNAD13593
Also note: The only truly safe formats for date/time literals in SQL Server, at least for datetime and smalldatetime, are: YYYYMMDD and YYYY-MM-DDThh:mm:ss[.nnn]
Reference: Bad habits to kick : mis-handling date / range queries - Aaron Bertrand
For example, if you have a language setting that implicitly sets the dateformat to dmy, then the same input for two different conversions can yield different output, if not an error:
set language 'british';
select toDatatype = 'datetime' ,val = convert(char(10),convert(datetime,'2017-06-01 00:00:00'),120)
union all
select toDatatype = 'date', val = convert(char(10),convert(date,'2017-06-01 00:00:00'),120)
returns:
+------------+------------+
| toDatatype | val |
+------------+------------+
| datetime | 2017-01-06 |
| date | 2017-06-01 |
+------------+------------+
and select convert(datetime,'2017-06-13') would return an error where as select convert(date,'2017-06-13') would return 2017-06-13.

Related

mySQL Workbench Error: Syntax Error, unexpected single quotes

I was trying to make a SQL statement in PHP, to convert a string into a time(6). But I have tried everything, for the last 12 hours, and have not made an inch of progress. I have tried these statements, all yield the same error.
UPDATE scheduling SET start='03:42PM' WHERE activityid=2;
UPDATE scheduling SET start=CONVERT(TIME(6),'03:42PM');
INSERT INTO scheduling(start) VALUES (start=CONVERT(TIME(6),'03:42PM'));
INSERT INTO scheduling(start) VALUES (start=CONVERT(TIME(6),'03:42PM'));
INSERT INTO scheduling(start) VALUES (start=CONVERT(TIME(6),'15:42'));
The error is
Syntax Error: unexpected '03:42PM'(single quoted text)"
I do not know how to fix this, the table exists, and i have sucesfully got other info using statements like SELECT activityid=2 FROM xxxxxx.scheudling
I guess I have two questions, either answer would work.
In my PHP document, how would I convert a string I get in from an Android Studio volley to a date. (I get the variable correctly, with $start=$_Post("start"), so that works, but I cant convert it into a time. I looked online, and tried everything that looked like it work work.
Conversion through SQL Code, I already tried CAST and CONVERT, neither works. My start column is type TIME(6).
I recommend testing expressions using a SELECT statement.
Firstly, the MySQL CONVERT function arguments are flipped around backwards.
The syntax is CONVERT(expr,type)
And type is supplied as a keyword, not a string literal. For example:
SELECT CONVERT('235',SIGNED)
To convert to a TIME datatype
SELECT CONVERT( '15:42' ,TIME(6)) // => 15:42:00.000000
The 'PM' part of the string literal will be ignored.
SELECT CONVERT( '03:42PM' ,TIME(6)) // => 03:42:00.000000
We can use the STR_TO_DATE function to return a TIME value from a string that contains the AM/PM indicator
SELECT STR_TO_DATE( '03:42PM' ,'%h:%i%p')
And there's no need to cast that to TIME(6), we can do this:
UPDATE scheduling
SET start = STR_TO_DATE( '03:42PM' ,'%h:%i%p')
WHERE activityid = 2
The STR_TO_DATE function is documented here:
https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_str-to-date
The format patterns for STR_TO_DATE are documented here, under DATE_FORMAT:
https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_date-format
FOLLOWUP
Demonstration:
setup
USE test;
CREATE TABLE scheduling (activityid INT PRIMARY KEY, start TIME(6));
-- 0 row(s) affected
INSERT INTO scheduling (activityid) VALUES (2);
-- 1 row(s) affected
execute the update statement in the answer above
UPDATE scheduling SET start = STR_TO_DATE( '03:42PM' ,'%h:%i%p') WHERE activityid = 2 ;
-- 1 row(s) affected
results
SELECT * FROM scheduling WHERE activityid = 2;
-- activityid start
-- ---------- ---------------
-- 2 15:42:00.000000
SECOND FOLLOWUP
Use same sql_mode setting reported by OP:
SET ##sql_mode = 'ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION' ;
Test:
SELECT STR_TO_DATE( '03:42PM' ,'%h:%i%p')
returns
(NULL)
But this more complicated expression:
SELECT TIME(STR_TO_DATE(CONCAT(CURRENT_DATE(),' ', '03:42PM' ),'%Y-%m-%d %h:%i%p'))
returns
15:42:00
The more complicated expression is a workaround to avoid behavior imposed by the STRICT_TRANS_TABLES and NO_ZERO_DATE in the sql_mode.

Different results - SQL Server and PHP (PEAR DB)

I'm trying to run a query using php pear db and is not returning any value. However, when I run using SQL Server I get the data
In PHP I'm already setting:
"SET ANSI_NULLS ON" and "SET ANSI_WARNINGS ON"
Query:
select A.nome, count(sa.id_sala) as Atendimentos, cast( avg( case when (coalesce(sa.dt_final, sa.dt_ping_internauta) > sa.dt_inicio_atendimento) then datediff(minute, coalesce(sa.dt_inicio_atendimento, sa.dt_inicio), coalesce(sa.dt_finalAtendimento, coalesce(sa.dt_final, sa.dt_ping_internauta)) ) else 0 end ) as money) as [media em minutos] from sala SA join atendente A on (A.id_atendente = SA.fk_id_atendente) where sa.interno = 0 and coalesce(sa.dt_inicio_atendimento, sa.dt_inicio) between '2012-01-01' and '2012-12-31' and SA.fk_id_empresa = 1 group by A.nome order by 2 desc
SOLVED
solution:
"The safe datetime string formats to use in SQL Server is
YYYYMMDD HH:MM:SS or YYYY-MM-DDTHH:MM:SS."
SQL Error : The conversion of a varchar data type to a datetime data type resulted in an out-of-range value
SOLVED
solution:
"The safe datetime string formats to use in SQL Server is
YYYYMMDD HH:MM:SS or YYYY-MM-DDTHH:MM:SS."
SQL Error : The conversion of a varchar data type to a datetime data type resulted in an out-of-range value

PHP mssql_query errors when converting date and/or time from character string

I am using PHP to query some data on SQL Server 2008 R2 and receiving the following errors:
PHP Warning: mssql_query(): message: Conversion failed when converting date and/or time from character string. (severity 16) in /var/www/html/BSC_Entry.php on line 14
PHP Warning: mssql_query(): General SQL Server error: Check messages from the SQL Server (severity 16) in /var/www/html/BSC_Entry.php on line 14
Here's the code block:
3 <?php // Initialise all database actions
4 //IP of server
5 $server = 'x.x.x.x';
6
7 // Connection to MSSQL - possibly use password file
8 $link = mssql_connect($server, 'user', 'pass');
9 if (!$link) {
10 die('Something went wrong while connecting to MSSQL');
11 }
12
13 // Declare query to return BSC_Name, BSC_Owner and
14 $qBSCInfo = mssql_query('SELECT * FROM dbo.BSC_Info;', $link);
15
16 ?>
Initially, I was passing the SQL below as a parameter to mssql_query, but after receiving the errors, created the database view above 'BSC_Info' (with appropriate permissions) in case the query was too complex for mssql_query to handle:
SELECT DISTINCT
dbo.BSC.BSC_ID,
dbo.BSC.BSC_Name,
dbo.BSC.BSC_Owner,
DATEDIFF(M, MAX(CONVERT(DATETIME, LEFT(dbo.BSCDataSet.DatePeriod, 4)
+ RIGHT(dbo.BSCDataSet.DatePeriod, 2) + '01')), CONVERT(DATETIME, LEFT(CONVERT(VARCHAR, GETDATE(), 120), 4) + RIGHT(LEFT(CONVERT(VARCHAR, GETDATE(),
120), 7), 2) + '01')) AS Periods_to_Current
FROM dbo.BSC
LEFT OUTER JOIN dbo.BSCDataSet
ON dbo.BSC.BSC_ID = dbo.BSCDataSet.BSC_ID
GROUP BY dbo.BSC.BSC_ID, dbo.BSC.BSC_Name, dbo.BSC.BSC_Owner
To clarify, the query works in SQL Server Management Studio returning some fields from a table along with the difference (in months) between the current date and an earlier date (stored in the database as a VARCHAR - YYYYMM format). In order to prevent any issues with partial months, I've set the compared dates to the first day of the month. I am sure there's a more graceful way of doing this, but I have very little SQL Server experience, or PHP for that matter!
Data types are:
BSC_ID - numeric(5,0)
BSC_Name - varchar(50)
BSC_Owner - varchar(50)
Periods_to_Current - int
Any help would be much appreciated. Cheers all!
So there were a number of issues with this code:
php.ini file needed the mssql setting: mssql.datetimeconvert = 0
Any CONVERT-ed date fields needed the date format 121
the original code tried to perform conversions, date arithmetic and MAX() functions on a potentially NULL date field - oops
I have now amended the code to a more appropriate (and working):
SELECT
dbo.BSC.BSC_ID,
dbo.BSC.BSC_Name,
dbo.BSC.BSC_Owner,
CASE maxview.maxDate
WHEN NULL THEN NULL
ELSE DATEDIFF(M,CONVERT(DATETIME, LEFT(maxview.maxdate, 4)+ RIGHT(maxview.maxdate, 2) + '01', 121),GETDATE())
END
FROM dbo.BSC
LEFT OUTER JOIN (SELECT BSC_ID, MAX(dbo.BSCDataSet.DatePeriod) as maxDate
FROM dbo.BSCDataSet GROUP BY BSC_ID) maxview
ON dbo.BSC.BSC_ID = maxview.BSC_ID;
Hopefully this will help someone out!

PHP TZ setting length

I was wonder what is the maximum length of the timezone settings in PHP? I'm storing the string in a database, and would like to keep the length as short as possible, but i see timezones like "Canada/East-Saskatchewan", which goes beyond our current limit.
If I could just get a list of all the supported timezone string, I can sort them, but they are currently split on to several different pages.
linky: http://www.php.net/manual/en/timezones.php
Edit June 2021 Answer is 64. Why? That's the width of the column used in MySQL to store those timezone name strings.
The zoneinfo database behind those time zone strings just added new prefixes. To America/Argentina/ComodRivadavia, formerly the longest timezone string, they added posix/America/Argentina/ComodRivadavia and right/America/Argentina/ComodRivadavia, both with a length of 38. This is up from 32, the previous longest string.
And here is the complete PHP code to find that:
<?php
$timezone_identifiers = DateTimeZone::listIdentifiers();
$maxlen = 0;
foreach($timezone_identifiers as $id)
{
if(strlen($id) > $maxlen)
$maxlen = strlen($id);
}
echo "Max Length: $maxlen";
/*
Output:
Max Length: 32
*/
?>
The Olson database — available from ftp://ftp.iana.org/tz/releases/ or http://www.iana.org/time-zones (but see also http://www.twinsun.com/tz/tz-link.htm* and http://en.wikipedia.org/wiki/Tz_database) — is the source of these names. The documentation in the file Theory includes a description of how the zone names are formed. This would help you establish how long names can be.
The longest 'current' names are 30 characters (America/Argentina/Buenos_Aires,
America/Argentina/Rio_Gallegos, America/North_Dakota/New_Salem); the longest 'backwards compatibility' name is 32 characters (America/Argentina/ComodRivadavia).
* Note that the TwinSun site has not been updated for some time and has some outdated links (such as suggesting that the Olson database is available from ftp://ftp.elsie.nci.nih.gov — it is now available from IANA instead).
From the manual:
<?php
$timezone_identifiers = DateTimeZone::listIdentifiers();
for ($i=0; $i < 5; $i++) {
echo "$timezone_identifiers[$i]\n";
}
?>
If you are using MySQL with PHP, consider that MySQL already stores Olson timezone names in the "mysql" system database, in a table called "time_zone_name", in a column called "name". One option is to choose the length of your column to match the length that MySQL uses. In MySQL 5.7, the timezone name length is 64 characters. To determine the length in use on your MySQL installation, follow the example below:
mysql> use mysql
Database changed
mysql> describe time_zone_name;
+--------------+------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------------+------------------+------+-----+---------+-------+
| Name | char(64) | NO | PRI | NULL | |
| Time_zone_id | int(10) unsigned | NO | | NULL | |
+--------------+------------------+------+-----+---------+-------+
2 rows in set (0.01 sec)

Using timestamp type with pg_prepare

Running the following code:
$preCallMatch = pg_prepare($dbcp, 'callMatch',
"SELECT duration
FROM voip_calls
WHERE system_id = $1
AND call_start => $2
AND call_start <= $3
AND destination = $4");
I get the following error:
Warning: pg_prepare(): Query failed: ERROR: operator does not exist: timestamp without time zone => "unknown"
HINT: No operator matches the given name and argument type(s). You may need to add explicit type casts. in /home/www/dinesh/UPSReconcileZeroSecondCalls.php on line 38
I have tried casting $2 in this manner with no luck:
$preCallMatch = pg_prepare($dbcp, 'callMatch',
"SELECT duration
FROM voip_calls
WHERE system_id = $1
AND call_start => CAST ( $2 AS TIMESTAMP )
AND call_start <= CAST ( $3 AS TIMESTAMP )
AND destination = $4");
Warning: pg_prepare(): Query failed: ERROR: operator does not exist: timestamp without time zone => timestamp without time zone
HINT: No operator matches the given name and argument type(s). You may need to add explicit type casts. in /home/www/dinesh/UPSReconcileZeroSecondCalls.php on line 38
Column types from voip_calls table:
call_start | timestamp without time zone |
call_end | timestamp without time zone | not null
Any tips as to what I'm doing wrong? Note, PDO or MDPD aren't an option right now.
Versions of software:
ii php5 5.2.6.dfsg.1-1+lenny3 server-side, HTML-embedded scripting languag
ii libapache2-mod-php5 5.2.6.dfsg.1-1+lenny3 server-side, HTML-embedded scripting languag
ii php5-pgsql 5.2.6.dfsg.1-1+lenny3 PostgreSQL module for php5
ii libpq5 8.3.8-0lenny1 PostgreSQL C client library
postmaster (PostgreSQL) 8.1.4
It may be your => operator causing the problem - try >= instead.
Also as a hint I find it easier to write $2::timestamp instead of CAST($2 AS TIMESTAMP) - it is a PostgreSQL-specific syntax but for me reads better (and it's less to type ;-) )
Turns out it was the <= and => operators. Doing this works fine:
$preCallMatch = pg_prepare($dbcp, 'callMatch',
"SELECT duration
FROM voip_calls
WHERE system_id = $1
AND call_start BETWEEN $2 AND $3
AND destination = $4");

Categories