Konvertierung von SQL Server-Zeichenfolgen in Datumsangaben

186

Ich möchte einen String wie folgt konvertieren:

'10/15/2008 10:06:32 PM'

in den entsprechenden DATETIME-Wert in SQL Server.

In Oracle würde ich Folgendes sagen:

TO_DATE('10/15/2008 10:06:32 PM','MM/DD/YYYY HH:MI:SS AM')

Diese Frage impliziert, dass ich die Zeichenfolge in eines der Standardformate analysieren und dann mit einem dieser Codes konvertieren muss. Das scheint für eine so weltliche Operation lächerlich. Gibt es einen einfacheren Weg?

JosephStyons
quelle

Antworten:

28

SQL Server (2005, 2000, 7.0) bietet keine flexible oder gar nicht flexible Möglichkeit, eine beliebig strukturierte Datumszeit im Zeichenfolgenformat in den Datentyp Datumszeit zu konvertieren.

Mit "willkürlich" meine ich "eine Form, die die Person, die sie geschrieben hat, obwohl vielleicht nicht Sie oder ich oder jemand auf der anderen Seite des Planeten, als intuitiv und völlig offensichtlich betrachten würde." Ehrlich gesagt bin ich mir nicht sicher, ob es einen solchen Algorithmus gibt.

Philip Kelley
quelle
32
Es gibt einen solchen Algorithmus, Oracle hat ihn bereits implementiert, und das Fehlen eines Äquivalents für SQL Server ist ein ständiger Schmerz.
Matao
19
@matao, bitte klären Sie uns auf, wie bestimmt Oracle auf magische Weise, ob ein Benutzer, der tippte 9/6/12, den 6. September 2012, den 9. Juni 2012, den 6. Dezember 2009 oder etwas anderes meinte?
Aaron Bertrand
13
Keine Sorge, hier: techonthenet.com/oracle/functions/to_date.php Natürlich muss es ein konsistentes Format sein, das Sie vom Entwickler angeben, aber weitaus flexibler als die Handvoll Formatmasken, die MS Ihnen bietet, was zu schmerzhaftem benutzerdefiniertem Parsen führt .
Matao
3
@JosphStyons war sich der TO_DATE-Funktion von Oracle bewusst, wie in seinem Beispiel gezeigt. Er wollte wissen, ob es eine Möglichkeit gibt, Datumsangaben als Zeichenfolgen zu konvertieren, ohne das Format / die Struktur der Zeichenfolge kennen zu müssen. SQL macht das nicht und es scheint sicher, dass Oracle TO_DATE es auch nicht macht.
Philip Kelley
23
@PhilipKelley Ich sehe nicht, wo das OP wissen will, wie es geht, ohne das Format kennen zu müssen. Er sagt ausdrücklich, dass er das Format kennt und fragt, ob SQL Server etwas hat, das TO_DATE entspricht, dh etwas, das es dem Entwickler ermöglicht, eine beliebige Formatzeichenfolge einzugeben.
Neverfox
305

Versuche dies

Cast('7/7/2011' as datetime)

und

Convert(varchar(30),'7/7/2011',102)

Weitere Informationen finden Sie unter CAST und CONVERT (Transact-SQL) .

gauravg
quelle
14
Dies ist der richtige Weg und sollte als die richtige Antwort markiert werden. Beachten Sie, dass dies Cast('2011-07-07' as datetime)auch funktioniert und die Unklarheit über die Reihenfolge von Monat und Tag beseitigt.
Joe DeRose
Dies funktioniert nicht, wenn der Monat> 12 ist. Die Formatierung erwartet das Format MM / TT / JJJJ
Chakri
Verwenden Sie Konvertieren (varchar (30), '7/7/2011', 103), wenn Sie von TT / MM / JJJJ konvertieren
Matias Masso
2
@Chakri, wenn Ihre Daten in TT / MM / JJJJ SET DATEFORMAT dmyvor Ihrer Anfrage verwendet werden
Nathan Griffiths
48

Führen Sie dies durch Ihren Abfrageprozessor. Es formatiert Daten und / oder Zeiten wie diese und eine davon sollte Ihnen das geben, wonach Sie suchen. Es wird nicht schwer sein, sich anzupassen:

Declare @d datetime
select @d = getdate()

select @d as OriginalDate,
convert(varchar,@d,100) as ConvertedDate,
100 as FormatValue,
'mon dd yyyy hh:miAM (or PM)' as OutputFormat
union all
select @d,convert(varchar,@d,101),101,'mm/dd/yy'
union all
select @d,convert(varchar,@d,102),102,'yy.mm.dd'
union all
select @d,convert(varchar,@d,103),103,'dd/mm/yy'
union all
select @d,convert(varchar,@d,104),104,'dd.mm.yy'
union all
select @d,convert(varchar,@d,105),105,'dd-mm-yy'
union all
select @d,convert(varchar,@d,106),106,'dd mon yy'
union all
select @d,convert(varchar,@d,107),107,'Mon dd, yy'
union all
select @d,convert(varchar,@d,108),108,'hh:mm:ss'
union all
select @d,convert(varchar,@d,109),109,'mon dd yyyy hh:mi:ss:mmmAM (or PM)'
union all
select @d,convert(varchar,@d,110),110,'mm-dd-yy'
union all
select @d,convert(varchar,@d,111),111,'yy/mm/dd'
union all
select @d,convert(varchar,@d,12),12,'yymmdd'
union all
select @d,convert(varchar,@d,112),112,'yyyymmdd'
union all
select @d,convert(varchar,@d,113),113,'dd mon yyyy hh:mm:ss:mmm(24h)'
union all
select @d,convert(varchar,@d,114),114,'hh:mi:ss:mmm(24h)'
union all
select @d,convert(varchar,@d,120),120,'yyyy-mm-dd hh:mi:ss(24h)'
union all
select @d,convert(varchar,@d,121),121,'yyyy-mm-dd hh:mi:ss.mmm(24h)'
union all
select @d,convert(varchar,@d,126),126,'yyyy-mm-dd Thh:mm:ss:mmm(no spaces)'
Taptronic
quelle
47

In SQL Server Denali können Sie etwas tun, das sich dem nähert, was Sie suchen. Sie können jedoch immer noch nicht einfach eine beliebig definierte verrückte Datumszeichenfolge übergeben und erwarten, dass SQL Server diese berücksichtigt. Hier ist ein Beispiel mit etwas, das Sie in Ihrer eigenen Antwort gepostet haben. Die FORMAT () -Funktion kann auch Gebietsschemas als optionales Argument akzeptieren. Sie basiert auf dem .NET-Format, sodass die meisten, wenn nicht alle Token-Formate vorhanden sind, die Sie erwarten.

DECLARE @d DATETIME = '2008-10-13 18:45:19';

-- returns Oct-13/2008 18:45:19:
SELECT FORMAT(@d, N'MMM-dd/yyyy HH:mm:ss');

-- returns NULL if the conversion fails:
SELECT TRY_PARSE(FORMAT(@d, N'MMM-dd/yyyy HH:mm:ss') AS DATETIME);

-- returns an error if the conversion fails:
SELECT PARSE(FORMAT(@d, N'MMM-dd/yyyy HH:mm:ss') AS DATETIME);

Ich empfehle Ihnen dringend, mehr Kontrolle zu übernehmen und Ihre Datumseingaben zu bereinigen. Die Tage, an denen Personen Datumsangaben in einem beliebigen Freetext-Formularfeld in einem beliebigen Format eingeben konnten, sollten inzwischen weit hinter uns liegen. Wenn jemand am 09.08.2011 eintritt, ist das der 9. August oder der 8. September? Wenn Sie sie dazu bringen, ein Datum in einem Kalendersteuerelement auszuwählen, kann die App das Format steuern. Unabhängig davon, wie sehr Sie versuchen, das Verhalten Ihrer Benutzer vorherzusagen, werden sie immer einen dümmeren Weg finden, um ein Datum einzugeben, das Sie nicht geplant haben.

Bis Denali denke ich jedoch, dass @Ovidiu bisher die besten Ratschläge hat ... dies kann durch die Implementierung Ihrer eigenen CLR-Funktion ziemlich trivial gemacht werden. Dann können Sie einen Fall / Schalter für so viele verrückte Nicht-Standardformate schreiben, wie Sie möchten.


UPDATE für @dhergert :

SELECT TRY_PARSE('10/15/2008 10:06:32 PM' AS DATETIME USING 'en-us');
SELECT TRY_PARSE('15/10/2008 10:06:32 PM' AS DATETIME USING 'en-gb');

Ergebnisse:

2008-10-15 22:06:32.000
2008-10-15 22:06:32.000

Sie müssen zuerst noch diese anderen wichtigen Informationen haben. Sie können natives T-SQL nicht verwenden, um festzustellen, ob der 6/9/20129. Juni oder der 6. September ist.

Aaron Bertrand
quelle
1
Ich denke, die Frage war, wie man eine Zeichenfolge in eine Datumszeit konvertiert, nicht eine Datumszeit in eine Zeichenfolge.
David Hergert
1
TRY_PARSE war perfekt. Wir hatten ein Problem beim Parsen eines Datums 'Do 22.09.2016', danke fürs Teilen!
Simon
11

Für dieses Problem ist die beste Lösung, die ich verwende, eine CLR-Funktion in SQL Server 2005 zu haben, die eine der Funktionen DateTime.Parse oder ParseExact verwendet, um den DateTime-Wert mit einem angegebenen Format zurückzugeben.

Ovidiu Pacurar
quelle
11

Benutze das:

SELECT convert(datetime, '2018-10-25 20:44:11.500', 121) -- yyyy-mm-dd hh:mm:ss.mmm

Die Umrechnungscodes finden Sie in der Tabelle in der offiziellen Dokumentation .

Simone
quelle
8

Warum nicht versuchen

select convert(date,'10/15/2011 00:00:00',104) as [MM/dd/YYYY]

Datumsformate finden Sie unter SQL Server Helper> SQL Server-Datumsformate

Scott Gollaglee
quelle
Ihr Codebeispiel funktioniert nicht. "Die Konvertierung ist beim Konvertieren von Datum und / oder Uhrzeit aus der Zeichenfolge fehlgeschlagen."
César León
5
Sollte sein select convert(date,'10/15/2011 00:00:00',101). Weitere Details zum Format und warum 101 finden Sie unter docs.microsoft.com/en-us/sql/t-sql/functions/…
anotherUser
1
Acht Personen haben diese Antwort gewählt und es funktioniert nicht einmal ...
David Klempfner
4

Ich habe eine Minute gebraucht, um das herauszufinden, also hier für den Fall, dass es jemandem helfen könnte:

In SQL Server 2012 und besser können Sie diese Funktion verwenden:

SELECT DATEFROMPARTS(2013, 8, 19);

So habe ich die Teile des Datums extrahiert, die in diese Funktion eingefügt werden sollen:

select
DATEFROMPARTS(right(cms.projectedInstallDate,4),left(cms.ProjectedInstallDate,2),right( left(cms.ProjectedInstallDate,5),2)) as 'dateFromParts'
from MyTable
Jared
quelle
3

Diese Seite enthält einige Verweise auf alle angegebenen Datums- / Uhrzeitkonvertierungen, die für die Funktion CONVERT verfügbar sind. Wenn Ihre Werte nicht in eines der akzeptablen Muster fallen, ist es meiner Meinung nach am besten, die ParseExact-Route zu wählen.

Tvanfosson
quelle
Link ist defekt.
Michael Potter
3

Persönlich, wenn Sie mit willkürlichen oder völlig unkonventionellen Formaten zu tun haben, vorausgesetzt, Sie wissen, was sie im Voraus sind oder werden, verwenden Sie einfach regexp, um die Abschnitte des gewünschten Datums abzurufen und eine gültige Datums- / Datums- / Uhrzeitkomponente zu bilden.

SyWill
quelle
1

Ich weiß, dass dies ein böser alter Beitrag mit vielen Antworten ist, aber viele Leute denken, dass sie entweder Dinge auseinander brechen und wieder zusammensetzen MÜSSEN oder darauf bestehen, dass es keine Möglichkeit gibt, die vom OP-Original angeforderte Konvertierung implizit durchzuführen .

Um andere mit derselben Frage zu überprüfen und hoffentlich eine einfache Antwort zu geben, fragte das OP, wie man '10 / 15/2008 10:06:32 PM 'in eine DATETIME konvertiert. Jetzt hat SQL Server einige Sprachabhängigkeiten für zeitliche Konvertierungen. Wenn die Sprache jedoch Englisch oder ähnliches ist, wird dies zu einem einfachen Problem. Führen Sie einfach die Konvertierung durch und sorgen Sie sich nicht um das Format. Zum Beispiel (und Sie können CONVERT oder CAST verwenden) ...

 SELECT UsingCONVERT = CONVERT(DATETIME,'10/15/2008 10:06:32 PM')
        ,UsingCAST   = CAST('10/15/2008 10:06:32 PM' AS DATETIME)
;

... und das ergibt die folgenden Antworten, die beide richtig sind.

Geben Sie hier die Bildbeschreibung ein

Wie sie in den Fernsehwerbespots sagen: "Aber warten Sie! Bestellen Sie noch nicht! Ohne zusätzliche Kosten kann es VIEL mehr!"

Lassen Sie uns die wahre Kraft zeitlicher Konvertierungen mit DATETIME sehen und den als DATETIME2 bekannten Fehler teilweise untersuchen. Schauen Sie sich die verrückten Formate an, die DATETIME automatisch verarbeiten kann und die DATETIME2 nicht. Führen Sie den folgenden Code aus und sehen Sie ...

--===== Set the language for this example.
    SET LANGUAGE ENGLISH --Same a US-English
;
--===== Use a table constructor as if it were a table for this example.
 SELECT *
        ,DateTimeCONVERT  = TRY_CONVERT(DATETIME,StringDT)
        ,DateTimeCAST     = TRY_CAST(StringDT AS DATETIME)
        ,DateTime2CONVERT = TRY_CONVERT(DATETIME2,StringDT)
        ,DateTime2CAST    = TRY_CAST(StringDT AS DATETIME2)
   FROM (
         VALUES
         ('Same Format As In The OP'    ,'12/16/2001 01:51:01 PM')
        ,('Almost Normal'               ,'16 December, 2001 1:51:01 PM')
        ,('More Normal'                 ,'December 16, 2001 01:51:01 PM')
        ,('Time Up Front + Spaces'      ,'   13:51:01  16 December   2001')
        ,('Totally Whacky Format #01'   ,'  16  13:51:01  December   2001')
        ,('Totally Whacky Format #02'   ,'  16    December 13:51:01  2001  ')
        ,('Totally Whacky Format #03'   ,'  16    December 01:51:01  PM 2001  ')
        ,('Totally Whacky Format #04'   ,' 2001 16    December 01:51:01  PM ')
        ,('Totally Whacky Format #05'   ,' 2001    December 01:51:01  PM  16  ')
        ,('Totally Whacky Format #06'   ,' 2001 16    December  01:51:01 PM  ')
        ,('Totally Whacky Format #07'   ,' 2001 16    December  13:51:01 PM  ')
        ,('Totally Whacky Format #08'   ,' 2001 16  13:51:01 PM  December    ')
        ,('Totally Whacky Format #09'   ,'   13:51:01   PM  2001.12/16 ')
        ,('Totally Whacky Format #10'   ,'   13:51:01   PM  2001.December/16 ')
        ,('Totally Whacky Format #11'   ,'   13:51:01   PM  2001.Dec/16 ')
        ,('Totally Whacky Format #12'   ,'   13:51:01   PM  2001.Dec.16 ')
        ,('Totally Whacky Format #13'   ,'   13:51:01   PM  2001/Dec.16')
        ,('Totally Whacky Format #14'   ,'   13:51:01   PM  2001 . 12/16 ')
        ,('Totally Whacky Format #15'   ,'   13:51:01   PM  2001 . December / 16 ')
        ,('Totally Whacky Format #16'   ,'   13:51:01   PM  2001 . Dec /   16 ')
        ,('Totally Whacky Format #17'   ,'   13:51:01   PM  2001 . Dec .   16 ')
        ,('Totally Whacky Format #18'   ,'   13:51:01   PM  2001 / Dec .   16')
        ,('Totally Whacky Format #19'   ,'   13:51:01   PM  2001 . Dec -   16 ')
        ,('Totally Whacky Format #20'   ,'   13:51:01   PM  2001 - Dec -   16 ')
        ,('Totally Whacky Format #21'   ,'   13:51:01   PM  2001 - Dec .   16')
        ,('Totally Whacky Format #22'   ,'   13:51:01   PM  2001 - Dec /   16 ')
        ,('Totally Whacky Format #23'   ,'   13:51:01   PM  2001 / Dec -   16')
        ,('Just the year'               ,' 2001      ')
        ,('YYYYMM'                      ,' 200112      ')
        ,('YYYY MMM'                    ,'2001 Dec')
        ,('YYYY-MMM'                    ,'2001-Dec')
        ,('YYYY    .     MMM'           ,'2001    .     Dec')
        ,('YYYY    /     MMM'           ,'2001    /     Dec')
        ,('YYYY    -     MMM'           ,'2001    /     Dec')
        ,('Forgot The Spaces #1'        ,'2001December26')
        ,('Forgot The Spaces #2'        ,'2001Dec26')
        ,('Forgot The Spaces #3'        ,'26December2001')
        ,('Forgot The Spaces #4'        ,'26Dec2001')
        ,('Forgot The Spaces #5'        ,'26Dec2001 13:51:01')
        ,('Forgot The Spaces #6'        ,'26Dec2001 13:51:01PM')
        ,('Oddly, this doesn''t work'   ,'2001-12')
        ,('Oddly, this doesn''t work'   ,'12-2001')
        ) v (Description,StringDT)
;

Also, ja ... SQL Server verfügt tatsächlich über eine ziemlich flexible Methode zur Verarbeitung aller Arten von seltsamen Zeitformaten, und es ist keine spezielle Behandlung erforderlich. Wir mussten nicht einmal die "PM" entfernen, die zu den 24-Stunden-Zeiten hinzugefügt wurden. Es ist "PFM" (Pure Freakin 'Magic).

Die Dinge variieren ein wenig, abhängig von der SPRACHE, die Sie für Ihren Server ausgewählt haben, aber eine ganze Menge davon wird so oder so behandelt.

Und diese "Auto-Magie" -Konvertierungen sind nichts Neues. Sie gehen einen sehr langen Weg zurück.

Jeff Moden
quelle
Eine böse neue Antwort auf eine böse alte Frage. Vielen Dank!
JosephStyons
Vielen Dank für das Feedback, @JosephStyons.
Jeff Moden
0

Wenn Sie möchten, dass SQL Server versucht, es herauszufinden, verwenden Sie einfach CAST CAST ('was auch immer' AS datetime). Dies ist jedoch im Allgemeinen eine schlechte Idee. Es gibt Probleme mit internationalen Daten, die auftauchen würden. Um diese Probleme zu vermeiden, möchten Sie, wie Sie festgestellt haben, das kanonische ODBC-Format des Datums verwenden. Das Format 120, 20 ist das Format für nur zweistellige Jahre. Ich glaube nicht, dass SQL Server eine integrierte Funktion hat, mit der Sie ein vom Benutzer angegebenes Format bereitstellen können. Sie können Ihre eigenen schreiben und möglicherweise sogar eine finden, wenn Sie online suchen.

Will Rickards
quelle
Wenn Sie internationale Daten in einer einzigen Spalte haben, stimme ich absolut zu, dass die Verwendung einer Formatnummer eine gute Idee ist. Wenn Sie internationale und US-amerikanische Daten in einer einzigen Spalte haben, können Sie den Unterschied zwischen 7/6/2000 und 6/7/2000 nur bestimmen, wenn Sie eine Schwesterspalte haben, in der das Format erläutert wird. Deshalb MUSS die Datenqualität an der Quelle einfach eine Sache sein. Wenn Sie wissen, dass Sie beispielsweise alle US-Daten haben, lassen Sie implizite Conversions ihre Sache machen. Wenn sie fehlschlagen, wissen Sie sicher, dass etwas in der Spalte repariert werden muss.
Jeff Moden
0

Konvertieren Sie die Zeichenfolge in MSSQL implizit in datetime

create table tmp 
(
  ENTRYDATETIME datetime
);

insert into tmp (ENTRYDATETIME) values (getdate());
insert into tmp (ENTRYDATETIME) values ('20190101');  --convert string 'yyyymmdd' to datetime


select * from tmp where ENTRYDATETIME > '20190925'  --yyyymmdd 
select * from tmp where ENTRYDATETIME > '20190925 12:11:09.555'--yyyymmdd HH:MIN:SS:MS


user12913610
quelle
Hallo und willkommen bei stackoverflow, und danke für die Antwort. Während dieser Code möglicherweise die Frage beantwortet, können Sie eine Erklärung hinzufügen, was das Problem ist, das Sie gelöst haben, und wie Sie es gelöst haben? Dies wird zukünftigen Lesern helfen, Ihre Antwort besser zu verstehen und daraus zu lernen.
Plutian
-4
dateadd(day,0,'10/15/2008 10:06:32 PM')
Jaroslaw
quelle
3
Willkommen bei StackOverflow! Bitte bearbeiten Sie Ihre Antwort , um eine Erklärung für Ihren Code hinzuzufügen. Diese Frage ist fast elf Jahre alt und hat bereits viele gut erklärte, positiv bewertete Antworten. Ohne eine Erklärung in Ihrer Antwort ist es von viel geringerer Qualität als diese anderen und wird höchstwahrscheinlich herabgestuft oder entfernt. Wenn Sie diese Erklärung hinzufügen, können Sie die Existenz Ihrer Antwort hier rechtfertigen.
Das_Geek
Ja, aber die "gut erklärten" Beiträge, auch die positiv bewerteten, sind viel zu komplex. Der hier gepostete ist tatsächlich einer der besseren, mit oder ohne Erklärung
Jeff Moden