0

MRvarcharという名前の列があります。を使用してクエリを実行すると、ORDER BY正しく順序付けされていないようです。

select MR, LName, FName from users 
  where MR between 'MR20001' and 'MR20002' 
  order by MR

結果:

MR20001   | LINA  | MARY
MR200011  | TEST  | CASE
MR20002   | KO    | MIKE

MR200011が前に表示されるのはなぜMR20002ですか?

4

3 に答える 3

5

MRは文字列であり、たとえば、数値を気にしないため、より24下位にソートされます。>のため、これは以前3の並べ替えのようなものです。SmithAzleazm

数値だけを数値として扱いたい場合は、MRプレフィックスを保存しないでください。列名に基づいて、これは完全に冗長に見えます。数値部分だけを として保存し、実行時INTに を追加するビューを作成してみませんか? 'MR'これは、アプリに実際に影響を与えることなく簡単に実行できます (ストアド プロシージャを介して挿入/更新操作を制御できない場合は、代わりにトリガーを追加します)。

CREATE VIEW dbo.users_appended
AS
    SELECT MR = 'MR' + CONVERT(VARCHAR(25), MR), 
        MRSort = MR --, ... other columns ...
      FROM dbo.users;
GO

SELECT MR, other columns
  FROM dbo.users_appended
  ORDER BY MRSort;

スキーマを変更できない場合は、次のように言えます。

ORDER BY CONVERT(BIGINT, SUBSTRING(MR, 3, 25));

MRしかし、そこに保管するべきではなかったと思います。これを変更できない場合は、文字列の数値部分を引き出すビューまたは計算列を検討してください。一般的に一方向のみに順序付けする場合は、計算列にインデックスを付けることもできます。

ALTER TABLE dbo.users ADD MRNumber
  AS (CONVERT(BIGINT, SUBSTRING(MR, 3, 25))) PERSISTED;

CREATE INDEX ix_mrnumber ON dbo.users(MRNumber);

計算された列とインデックスを維持するために必要な作業が、これがクエリに与える違いによって正当化されるかどうかをテストする必要があります。

ビューは似ていますが、インデックスから効率は得られません。

CREATE VIEW dbo.users_extended
AS
  SELECT MR, ..., MRNumber = CONVERT(BIGINT, SUBSTRING(MR, 3, 25));
GO

SELECT MR, ... 
  FROM dbo.users_extended
  ORDER BY MRNumber;

代わりに使用LENする場合は注意してください。コードはより単純ですが、必ずしもより効率的であるとは限りません。私のシステムでは、値の分布が広い 2 つのテーブルを作成しました。

SELECT 'MR'+RTRIM(ABS(object_id)) AS MR 
  INTO dbo.flab 
  FROM sys.all_objects -- 2096 rows

SELECT 'MR'+RTRIM(ABS(s1.object_id)) AS MR 
  INTO dbo.mort 
  FROM sys.all_objects AS s1
  CROSS JOIN sys.all_objects AS s2; -- 4397409 rows

ここで、次のような単純なクエリをテストします。

SELECT * FROM dbo.flab ORDER BY LEN(MR), MR;
SELECT * FROM dbo.flab ORDER BY CONVERT(BIGINT, SUBSTRING(MR, 3, 25));
SELECT * FROM dbo.mort ORDER BY LEN(MR), MR;
SELECT * FROM dbo.mort ORDER BY CONVERT(BIGINT, SUBSTRING(MR, 3, 25));

ヒープの結果 (推定コストに関して SQL Server が吐き出すナンセンスにもかかわらず、期間と CPU に細心の注意を払ってください):

ここに画像の説明を入力

そして、上のクラスター化インデックスでMR

ここに画像の説明を入力

BIGINTまた、部分文字列が 12 文字を超える潜在的な危険を回避するために、すべての計算を に変更しました(それでも、高価な - はい、高価な - を回避しますLEN())。推定コストは 50/50 であり、INT代わりに を使用した場合、期間の差はほぼ同じであることに注意してくださいBIGINT(使用しても安全であるとINT仮定します。値)。

于 2013-01-22T02:37:25.910 に答える
1

キャストしてみて、

select MR, LName, FName 
from users 
where MR between 'MR20001' and 'MR20002' 
order by CAST(REPLACE(MR, 'MR', '') AS INT)
于 2013-01-22T02:34:19.803 に答える
0

高価なキャストと置換をすべて回避するには、これを代替手段として使用できます。

select MR, LName, FName 
from Table1 
order by LEN(MR),MR

http://www.sqlfiddle.com/#!3/ae729/6

于 2013-01-22T02:49:59.883 に答える