2016-05-26 6 views
1

GenAmpsとGenVoltsをベースにした各ジェネレーターの月額料金を提供するレポートを作成しています。マイプライシングテーブルにGenAmps#とGenVoltサイズがある場合は、月額料金が入力されます。私の価格設定テーブルに見つからないGenAmps#とGenVoltsの値がある場合は、以下のようなケースがあります。これが発生すると、GenlyVoltsの値が等しい最も近いGenAmps#からMonthlyRateを引っ張ってほしい、ex(GenAmps 15、GenVolts KW)は価格表にはないので、MonthlyRateを(GenAmps 20、GenVolts KW)フィールドの1つがヌルで、値が必要な場合に最も近い数値を見つけます。

GenAmps GenVolts PricingGenAmp PricingGenVolt MonthRate(160hr) 
10  KW   NULL    NULL   NULL 
15  KVA   NULL    NULL   NULL 

これは、彼らが価格表のGenAmps#とGenVolts値を見つけることができないならば、私のレポートは次のようになります。

GenAmps GenVolts MonthRate(160hr) 
    25  KVA   1251 
    20  KW   1251 

(上記は価格表のものです)。これらは価格表にはないので、私は10KWが月額料金を20KWから15KVAを25KVAから引き上げることを望んでいます。したがって、次のようになります。

GenAmps GenVolts PricingGenAmp PricingGenVolt MonthRate(160hr) 
10  KW   20    KW    1251 
15  KVA   25    KVA    1251 

クエリが正しく動作しているときは、上のデータのようになります。

価格表に記載されていないGenAmps#が10〜900の範囲です。

これは私が現在持っているクエリですので、データを見た目に見せるように改訂する必要があります。

SELECT  TOP (100) PERCENT ContractID, SaleRep, GenAmps, GenVolts, GenPhase, EstRunningHours, MonthlyRate, DeliveryRate, PickupRate, FuelRate, DropCharge, HourlyServiceRate, 
         CASE WHEN gr.PricingGenAmps IS NULL THEN 
          (SELECT  MAX(GenAmps) AS a1 
           FROM   dbo.GeneratorSizePrices AS a 
           WHERE  (GenAmps < gr.GenAmps) AND a.GenVolts = gr.GenVolts) ELSE gr.PricingGenAmps END AS PricingGenAmp, ISNULL([MonthRate(160hr)], 
          (SELECT  [MonthRate(160hr)] 
           FROM   dbo.GeneratorSizePrices AS b 
           WHERE  (GenAmps = 
                  (SELECT  MAX(GenAmps) AS a 
                   FROM   dbo.GeneratorSizePrices 
                   WHERE  (GenAmps < gr.GenAmps) AND (GenVolts = gr.GenVolts))))) AS Month 
FROM   dbo.Elliott_GensRentalRate AS gr 
GROUP BY ContractID, SaleRep, GenAmps, GenVolts, GenPhase, EstRunningHours, MonthlyRate, DeliveryRate, PickupRate, FuelRate, DropCharge, HourlyServiceRate, PricingGenAmps, [MonthRate(160hr)] 
ORDER BY PricingGenAmps, GenAmps 
+0

ここから始めましょう。 http://spaghettidba.com/2015/04/24/how-to-post-at-sql-question-on-a-public-forum/ –

+0

"...最も近いGenAmpsから引っ張ってください#ここでGenVoltsの値等しく... "テーブルで見つかった次の高いGenAmps値、または表にない値からの最小デルタを持つGenAmps値を意味しますか?つまり、テーブルの「最も近い」値がテーブル内の値よりも小さい場合は、テーブル内の値を小さくしますか? Seanが示唆しているように、実際にはもっと詳細が必要です。 –

+0

2人の後者。テーブル内の値から最小のデルタを持つ値は何でも。テーブル内の値より小さいか大きいかは関係ありません。 @ JimtheFrayed – ETA

答えて

1

残りのクエリで何が起こっているのか分かりません。しかし、ある行を別の表の最も近い行と突き合わせることを含む問題の部分には、この方法で近づけることができます。

select * 
from 
    dbo.Elliott_GensRentalRate as gr cross apply 
    (
     select gsp.*, row_number() over 
      (order by abs(gr.GenAmps - gsp.GenAmps), sign(gr.GenAmps - gsp.GenAmps)) as rnk 
     from dbo.GeneratorSizePrices as gsp 
     where gsp.GenVolts = gr.GenVolts 
) as gspr /* GeneratorSizePricesRanked */ 
where gspr.rnk = 1 

cross applyは、私たちは、クエリの外だgrテーブルからGenAmpsの値を見てみましょう。 cross applyが利用できないときにこれを達成する他の方法がありますが、これはより効率的である可能性が非常に高いです。キーは、潜在的な一致を差の絶対値でランク付けし、次に出て来たものだけを上に保つことです。

私はsign()関数を使用して、より高いまたはより低いマッチが好ましいかどうかを判断しました。書かれているように、それは切り上げを好むでしょう。なんらかの理由で一致が見つからない場合がある場合は、outer applyを使用することもできます。

+0

sgnとは何ですか?それは機能ですか? @ shawnt00 – ETA

+0

@ETAこれは 'sign()'だったはずです。他のプラットフォームでは 'sgn()'がよくあります。 – shawnt00

+1

これははるかに滑らかできれいだった。ありがとうございました。これによりコードが大幅に単純化されました。 – ETA

0

これはあなたを開始するはずです。しかし、すべてのデータがなくても決定するのは難しいです。乾杯!

IF OBJECT_ID('tempdb..#gens') IS NOT NULL DROP TABLE #gens 
IF OBJECT_ID('tempdb..#genPrice') IS NOT NULL DROP TABLE #genPrice 

CREATE TABLE #gens(
    GenAmps INT, 
    GenVolts VARCHAR (3), 
    PricingGenAmp INT null, 
    PricingGenVolt VARCHAR (3) null, 
    MonthRate DECIMAL (6,2) null) 

CREATE TABLE #genPrice(
    GenAmps INT, 
    GenVolts VARCHAR (3), 
    MonthRate DECIMAL (6,2)) 

INSERT INTO #gens 
VALUES(10,'KW',null,null,null),(15,'KVA',null,null,null) 

INSERT INTO #genPrice 
VALUES(25,'KVA',1251.00),(20,'KW',1151.00) 



SELECT 
    g.GenAmps, 
    g.GenVolts, 
    ISNULL(g.PricingGenAmp,(SELECT MIN(gp.GenAmps) FROM #genPrice gp WHERE g.GenVolts = gp.GenVolts and gp.GenAmps > g.GenAmps)) AS PricingGenAmp, 
    ISNULL(g.PricingGenVolt,(SELECT GenVolts FROM #genPrice gp2 WHERE gp2.GenAmps = (SELECT MIN(gp.GenAmps) FROM #genPrice gp WHERE g.GenVolts = gp.GenVolts and gp.GenAmps > g.GenAmps))) as PricingGenVolt, 
    ISNULL(g.MonthRate,(SELECT MonthRate FROM #genPrice gp3 WHERE gp3.GenAmps = (SELECT MIN(gp.GenAmps) FROM #genPrice gp WHERE g.GenVolts = gp.GenVolts and gp.GenAmps > g.GenAmps))) as MonthRate 
FROM 
    #gens g 
+0

この手法はいくつかの理由で良くありません。 1)1つだけが必要なときにGenPriceへの結合が非常に多くなり、パフォーマンスが低下します。 2)これらの余分な結合のために理解しにくい3)誤って結合条件が間違ってしまうのは簡単すぎる。 4)重複したMIN(GenAmps)値が存在する場合(間違っているとわかっています)、完全に壊れてしまいます(このクエリの問題よりもコーディングスタイルが悪いです)。 – ErikE

関連する問題