2016-04-11 20 views
1

私はISNUMERIC SQLサーバの機能に問題があります。ISNUMERIC関数のバグ?

私はnvarcharタイプの1つの列を含むテーブルを持っています。

WITH CTE AS (
    SELECT * 
    FROM MyTable 
    WHERE ISNUMERIC([Column1]) = 1 
) 
SELECT * 
FROM CTE 
WHERE CAST(cte.Column1 AS INT) > 8000 

しかし、このクエリは、このエラーメッセージを返します:

error converting data type nvarchar 'LK' to int 

私の期待はある。このコラムでは、私はこのような値123241、...そして時にはLK 私のクエリのような文字列値を持ちます、Commonテーブル式はすべての行をフィルタリングします.Column1は数値で文字列ではありませんか?それが正しいか?

このエラーはなぜ発生しますか?

+0

それは、シーケンスSQL ServerはSQLを解析し、実行するに関係しています。確かめたい場合は、CTEの代わりに一時テーブルを使用する必要があります。または、サーバーのバージョンに応じて、アクセス権があれば試してみてください。 しかしISNUMERICはそうあなたのコードは、同様 –

+0

他の場所で失敗する私の問題を解決するSQLサーバーのいずれかの代替機能があるあなたがINTする解析できないもののために1を返すことができることに注意してください? – Kaja

+0

使用しているSQL Serverのバージョンは? –

答えて

3

これは実際にはバグではありません。

CTEは一時的なビューです(または一時的なビューのように動作します)。ビューを照会するようなクエリを考えてみましょう。ほとんどの場合、SQLはまずすべての行を調べ、両方のスカラー(isnumericとcast)から結果を取得してからフィルタリングに進みます。

キャストのデータをフィルタリングしようとすると、それは失敗に終わります。

あなたはそれだけで動作し、一時テーブルまたはテーブル変数に前のデータをフィルタリングしたい場合は

私は、クエリの下に、より効率的であることを考える
+0

ありがとうございましたが、私は副選択で同じ問題があります。何を説明したの? – Kaja

+1

@Kajaはい、副選択欄に同じ問題があります。 Subselects *は現代のDBエンジンでは一時テーブルを作成しません。 – Luaan

0
IF OBJECT_ID('dbo.tbl', 'U') IS NOT NULL 
    DROP TABLE dbo.tbl 
GO 

CREATE TABLE dbo.tbl (val NVARCHAR(1000)) 
INSERT INTO dbo.tbl 
VALUES ('123'), ('234'), ('LK'), ('8001') 

ALTER TABLE dbo.tbl 
    ADD val2 AS CASE WHEN ISNUMERIC(val) = 1 THEN CAST(val AS INT) END 
GO 

SELECT * 
FROM dbo.tbl 
WHERE val2 > 8000 
-2

SELECT * 
FROM MyTable 
WHERE ISNUMERIC([Column1]) = 1 AND CAST(cte.Column1 AS INT) > 8000 
+0

このクエリは、OPに投稿されたものとまったく同じエラーを返します – Raj

0

SQL Serverを避けるために、TOP Xを追加することにより、CTE表をマテリアライズする強制できる条件が「ショート」にするために場所を最適化します行動様式。

WITH CTE AS (
    SELECT TOP 10000000000000 
     * 
    FROM (VALUES('1'), ('LK')) t(Column1) 
    WHERE ISNUMERIC([Column1]) = 1 
) 
SELECT * 
FROM CTE 
WHERE CAST(cte.Column1 AS INT) > 8000 
0

これは、クエリが解析され実行される方法と関係があります。 Devartによって提案されたように列を追加することができない場合は、一時表を使用することもできます。

CREATE TABLE MyTable 
(
Column1 nvarchar(50) 
) 

INSERT INTO MyTable 
    VALUES ('123'), 
    ('241'), 
    ('LK'), 
    ('786'), 
    ('54321'), 
    ('7999'), 
    ('8001') 

SELECT 
    * INTO #TEMP 
FROM MyTable 
WHERE ISNUMERIC([Column1]) = 1 

SELECT 
    * 
FROM #TEMP 
WHERE CAST(Column1 AS int) > 8000 

DROP TABLE #TEMP 
0

主な問題は、SQLは操作上の順序が非常に少ない宣言型言語であることです。これは、エンジンがクエリを最適化できるようにするために必要です。短絡が働く

一つのケースはcase文です。ですから、このような何かを試すことができます。

drop table #tbl; 

create table #tbl (txt varchar(10)) 
insert into #tbl 
values ('123'), ('234'), ('LK'), ('9001') 

select * from #tbl 
where 
(
    case 
    when isnumeric(txt) = 1 then 
    case when cast(txt as int) > 8000 then 1 end 
    end 
) = 1 

でも、私はパフォーマンスが動作するように起こっているかを伝えることはできません。可能な場合は一般的に、あなたは本当に正規化されたデータを使用する必要があります - それは、SQLデータベースが本当に輝くことができます:)