Typickou odpovědí je přidat klauzuli WHERE:
WHERE ISDATE(a.valor) = 1
To je však ve vaší situaci problematické z několika důvodů:
-
ISDATE()
nemusí nutně odpovídat požadovanému způsobu v závislosti na regionálním nastavení serveru, jazyku uživatele nebo možnostech formátu data atd. Například:SET DATEFORMAT dmy; SELECT ISDATE('13/01/2012'); -- 1 SET DATEFORMAT mdy; SELECT ISDATE('13/01/2012'); -- 0
-
Nemůžete skutečně ovlivnit, že se SQL Server pokusí provést
CONVERT
po filtru.
Nemůžete ani použít poddotazy nebo CTE k pokusu oddělit filtr od CONVERT, protože SQL Server může optimalizovat operace v dotazu v jakémkoli pořadí, které považuje za efektivnější.
Například u omezeného vzorku pravděpodobně zjistíte, že to funguje dobře:
SET DATEFORMAT dmy;
SELECT valor, valor_date FROM (
SELECT valor, valor_date = CONVERT(DATE,
CASE WHEN ISDATE(valor) = 1 THEN valor ELSE NULL END, 103)
FROM dbo.mytable
WHERE ISDATE(valor) = 1
) AS sub WHERE valor_date BETWEEN '01/01/2012' AND '01/03/2012';
Ale i s touto konstrukcí jsem viděl případy, kdy se SQL Server pokusil nejprve vyhodnotit filtr, což vedlo ke stejné chybě, jakou aktuálně dostáváte.
Několik bezpečnějších řešení:
Přidejte vypočítaný sloupec, např.
ALTER TABLE dbo.mytable ADD valor_date
AS CONVERT(DATE, CASE WHEN ISDATE(valor) = 1 THEN valor
ELSE NULL END, 103);
Abyste se ochránili před možnými nesprávnými interpretacemi za běhu, měli byste před zadáním dotazu, který odkazuje na vypočítaný sloupec, zadat dateformat, např.
SET DATEFORMAT dmy;
SELECT valor, valor_date FROM dbo.mytable WHERE ...;
Vytvořte zobrazení:
CREATE VIEW dbo.myview
AS
SELECT valor, valor_date = CONVERT(DATE,
CASE WHEN ISDATE(valor) = 1 THEN valor ELSE NULL END, 103)
FROM dbo.mytable
WHERE ISDATE(valor) = 1;
Opět budete chtít vydat SET DATEFORMAT
při dotazu na zobrazení.
Použijte časovou tabulku:
SELECT <cols>
INTO #foo
FROM dbo.mytable
WHERE ISDATE(valor) = 1;
SELECT <cols>, CONVERT(DATE, valor) FROM #foo WHERE ...;
Můžete stále chtít použít DATEFORMAT
abyste se ochránili před konflikty mezi ISDATE
a uživatelská nastavení.
A ne, neměli byste zkuste ověřit své řetězce jako data pomocí shody vzorů řetězců, jak bylo navrženo v jiné (nyní smazané) odpovědi:
like '%__/%' or like '%/%'
Pro zpracování všech platných dat včetně přestupných let budete muset mít poměrně složité a náročné ověření.