4

BigMacs nvarchar(255)列を持つMSSQLテーブルMcTableがあります。BigMacsの値が5より大きい行を取得したいと思います。

私がしていることは:

select * from
  (
    select 
      BigMacs BigMacsS, 
      CAST(BigMacs as Binary) BigMacsB, 
      CAST(BigMacs as int) BigMacsL
    from 
      McTable
    where 
      BigMacs Like '%[0-9]%'
  ) table
where 
  Cast(table.BigMacsL as int) > 5 

その結果、エラーが発生します。

状態1、67行目nvarchar値'***'をデータ型intに変換するときに変換に失敗しました。

しかし、最後のフィルターを削除するwhere Cast(table.BigMacsL as int) > 5と機能し、次の結果が得られます。

6 0x360000000000000000000000000000000000000000000000000000000000 6
23 0x320033000000000000000000000000000000000000000000000000000000 23
22 0x320032000000000000000000000000000000000000000000000000000000 22
24 0x320034000000000000000000000000000000000000000000000000000000 24
25 0x320035000000000000000000000000000000000000000000000000000000 25
3 0x330000000000000000000000000000000000000000000000000000000000 3
17 0x310037000000000000000000000000000000000000000000000000000000 17
17 0x310037000000000000000000000000000000000000000000000000000000 17
19 0x310039000000000000000000000000000000000000000000000000000000 19
20 0x320030000000000000000000000000000000000000000000000000000000 20
659 0x360035003900000000000000000000000000000000000000000000000000 659
1 0x31000000000000000000000000000000000000000000000000000000000000 1
43 0x340033000000000000000000000000000000000000000000000000000000 43
44 0x340034000000000000000000000000000000000000000000000000000000 44
45 0x340035000000000000000000000000000000000000000000000000000000 45
46 0x340036000000000000000000000000000000000000000000000000000000 46
47 0x340037000000000000000000000000000000000000000000000000000000 47
44 0x340034000000000000000000000000000000000000000000000000000000 44
44 0x340034000000000000000000000000000000000000000000000000000000 44
47 0x340037000000000000000000000000000000000000000000000000000000 47
43 0x340033000000000000000000000000000000000000000000000000000000 43
50 0x350030000000000000000000000000000000000000000000000000000000 50
44 0x340034000000000000000000000000000000000000000000000000000000 44

そして、最初のクエリで'select*from'から'selecttop 18 * from'に変更すると、エラーも発生しません。

何が問題なのか、どうやって動かすのかわかりません!手伝っていただけませんか?

繰り返しになりますが、ここで達成しようとしているのは、BigMacsの値が5より大きいこれらのMcTable行を取得することです。

アップデート

このエラーを再現する手順:

データベースでこのエラーを簡単に取得できるように、クエリを用意しました。

データベースTestDBを作成し、次のコマンドでテーブルを作成します。

USE [TestDB]
GO
/****** Object:  Table [dbo].[TestTable]    Script Date: 04/08/2009 16:27:40 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[TestTable](
    [ID] [int] IDENTITY(1,1) NOT NULL,
    [MyVal] [nvarchar](255) COLLATE Polish_CI_AS NOT NULL,
 CONSTRAINT [PK_TestTable] PRIMARY KEY CLUSTERED 
(
    [ID] ASC
)WITH (PAD_INDEX  = OFF, IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]

次の値を挿入します:

delete from TestDB.dbo.TestTable
insert into TestDB.dbo.TestTable (MyVal) values ('fd')
insert into TestDB.dbo.TestTable (MyVal) values ('54543534')
insert into TestDB.dbo.TestTable (MyVal) values ('fat3tv3gv5')
insert into TestDB.dbo.TestTable (MyVal) values ('fdf4v43 4v434v')
insert into TestDB.dbo.TestTable (MyVal) values (' g dfg dfg df')
insert into TestDB.dbo.TestTable (MyVal) values ('f sd 4t4gsdf')
insert into TestDB.dbo.TestTable (MyVal) values ('f df 4 trwefg')
insert into TestDB.dbo.TestTable (MyVal) values ('f sd f4  fgsfg sd')
insert into TestDB.dbo.TestTable (MyVal) values ('54534534')
insert into TestDB.dbo.TestTable (MyVal) values ('454')

このクエリ:

    select 
        CAST(MyVal as int) MyValInt 
    from 
        dbo.TestTable 
    where 
        IsNumeric(MyVal) = 1

以下に示すように、有効な数値になります。

54543534

54534534

454

そして、このクエリでフィルタリングされた値を取得しようとすると、次のようになります。

select 
    * 
from
    (
        select 
            CAST(MyVal as int) MyValInt 
        from 
            dbo.TestTable 
        where 
            IsNumeric(MyVal) = 1
    ) tabela
where 
    tabela.MyValInt > 6

発生しないはずの次のエラーが発生するはずです。

メッセージ245、レベル16、状態1、行1 nvarchar値'fd'をデータ型intに変換するときに、変換に失敗しました。

4

9 に答える 9

6

改訂されたスクリプトに対する新しい回答。何が起こっているかというと、SQL Server クエリ オプティマイザがサブクエリを最適化しています。テスト テーブルの 1 回のスキャンを実行し、内側と外側の WHERE 句を 1 つに結合します。そのため、まだエラーが発生します。これを確認するには、クエリの推定実行計画を表示し、[クラスター化インデックス スキャン] アイコンにカーソルを合わせて、実際に実行されている内容を確認します。次の述語がスキャンに適用されていることがわかります。

CONVERT(int,[testdb].[dbo].[TestTable].[MyVal],0)>(6)
AND isnumeric(CONVERT_IMPLICIT(varchar(510),
    [testdb].[dbo].[TestTable].[MyVal],0))=(1)

したがって、クエリの構造に関係なく、テーブル内のすべての行で CAST/CONVERT を実行しようとしています...

これを回避するには、最適化できないテーブル変数または一時テーブルを使用します。

DECLARE @integers table (
    MyValInt int
)

INSERT
INTO    @integers
SELECT  CAST(MyVal AS int)
FROM    dbo.TestTable 
WHERE   ISNUMERIC(MyVal) = 1

SELECT  *
FROM    @integers
WHERE   MyValInt > 6

実際に返したい結果セットは異なるため、主キーを int 値とともにテーブル変数に格納し、最終的なクエリを次のような結合として実行することをお勧めします。

DECLARE @integers table (
    ID int,
    MyValInt int
)

INSERT
INTO    @integers
SELECT  ID, CAST(MyVal AS int)
FROM    dbo.TestTable 
WHERE   ISNUMERIC(MyVal) = 1

SELECT  b.*
FROM    @integers t
        INNER JOIN
                TestTable b
                ON b.ID = t.ID
WHERE   t.MyValInt > 6
于 2009-04-08T15:36:45.993 に答える
2

状態 1、行 67 nvarchar 値 '***' をデータ型 int に変換するときに変換に失敗しました。

の値の一部に数値以外の値が含まれているため、この値を取得していBigMacs.BigMacます。あなたの場合は「***」です。

そして、最初のクエリで「select * from」を「select top 18 * from」に変更しても、エラーは発生しません!

これは、少なくとも最初に返される 18 行に数値があるためBigMacs.BigMacです。

isReallyNumeric()と呼ばれる新しいユーザー定義メソッドを作成します。これは、実際に数値であるかどうかに対処します。

isReallyNumeric()関数を使用して数値の BigMac のみを除外するCTE (Common Table Expression) を使用して、一度整数
にキャストするようにクエリを最適化しました。BigMacs.BigMac

with NumericBigMacs as (
    select 
      BigMacs as BigMacsS, 
      CAST(BigMacs as Binary) as BigMacsB, 
      CAST(BigMacs as int) as BigMacsL
    from 
      McTable
    where 
      -- Filter only numeric values to compare.
      -- BigMacs Like '%[0-9]%'
      dbo.isReallyNumeric(BigMacs) = 1
)
select  *
from    NumericBigMacs NBM
where   BigMacsL > 5
于 2009-04-08T12:04:41.383 に答える
1

OK isnumeric は、文字データと数値を同じ列に格納する場合に常に機能するとは限りません。また、整数に変換できる項目に限定されません。説明については、次のリンクを参照してください: http://www.tek-tips.com/faqs.cfm?fid=6423

私の最初の質問は、数値と文字として使いたいものを同じ列に格納するのはなぜですか? これは重大な設計上の欠陥であり、可能であれば修正する必要があります。

このリンクは、構造を変更できない場合に何をすべきかを理解するのに役立つと思います。

于 2009-04-08T13:37:56.183 に答える
1

問題は、実際に int が含まれている場合にのみ、値を int にキャストできることです。明らかに最初の 18 行がそうです。ただし、さらに行を含めると、値を int にキャストできない行に到達し、説明したエラーが発生します。これはどう:

select 
      BigMacs BigMacsS, 
      CAST(BigMacs as Binary) BigMacsB 
    from 
      McTable
    where 
      BigMacs Like '%[6-9]%'
    or
      BigMacs LIKE '%[1-9][0-5]%'

これにより、この列のテキスト内に 5 より大きい数値を含むすべての行が検索されます (小数や負の数値が含まれていないと仮定します)。

于 2009-04-08T11:57:34.303 に答える
0

これは期待される結果を与えるようです

編集

where句が含まれています

DECLARE @McTable TABLE (BigMacs VARCHAR(20))

INSERT INTO @McTable VALUES ('1')
INSERT INTO @McTable VALUES ('1dqsf')
INSERT INTO @McTable VALUES ('qsfsq1')
INSERT INTO @McTable VALUES ('10')

select   
  BigMacs,
  cast(BigMacs as Binary) as BigMacsB, 
  cast(BigMacs as int) as BigMacsL
from @McTable
where IsNumeric(BigMacs) = 1
      and cast(BigMacs as int) > 5
于 2009-04-08T12:00:21.037 に答える
0

何が起こっているかを次に示します。述語BigMacs Like '%[0-9]%'は、あなたが考えていることをまったく実行しません。文字列のどこかに少なくとも 1 つの数字がある行を選択します。

これはあなたが望むものではありません。数字のみの文字列が必要です。残念ながら、LIKE ワイルドカードでは、それを求める簡単な方法はありません。

私たちはあなたの問題に十分に近づくかもしれません。私たちが求めるなら

not (BigMacs like "%[A-Za-z!@#$%^&*()=;:'""]%") 

数字以外のほとんどの行を除外します。"ほとんど" は、like ワイルドカードに数字以外のすべての文字が含まれているわけではないためです。これにより、キャストが機能するようになります。

そう:

select * from
  (
    select 
      BigMacs BigMacsS, 
      CAST(BigMacs as Binary) BigMacsB, 
      CAST(BigMacs as int) BigMacsL
    from 
      McTable
    where 
      not (BigMacs like "%[A-Za-z!@#$%^&*()=;:'""]%") 
  ) table
where 
  Cast(table.BigMacsL as int) > 5
于 2009-04-08T12:07:17.727 に答える
0

ISNUMERIC()関数を使用することも役立つと思います。

例:

SELECT * FROM
(
    SELECT CAST(CASE WHEN ISNUMERIC(myval)=1 THEN myval ELSE 0 END AS INT) AS mi
    FROM dbo.TestTable 
) AS t2
WHERE mi>5
于 2009-04-08T12:10:00.590 に答える
0

そのコードは機能するはずです:

select
    tabela.*
from
    (
        select
                CAST(MyVal as int) MyValInt
        from
                dbo.TestTable
        where
                IsNumeric(MyVal) = 1
    ) tabela
    left join (select 1 a )a on tabela.MyValInt > 6

元のクエリが失敗する理由は、クエリが SQL によって評価される順序に関連している可能性があると思います。

于 2009-04-08T16:24:43.520 に答える