सम्प्रदाय वितरण गणना

वोट
0

कुछ पृष्ठभूमि कहानी: कंपनी एक एक चुनौती के विजेताओं को वाउचर बाहर देता है। एसक्यूएल कि मैं वर्तमान जरूरतों को लिख रहा हूँ आवश्यक वाउचर मज़हब है कि मूल्य के लिए रकम एक व्यक्ति को सम्मानित तय करने के लिए। मैं एक मेज कि दुकानों मूल्यवर्ग वाउचर के लिए उपलब्ध, देश और मुद्रा के आधार पर की है।

नीचे दिए गए उदाहरण में, एक विशेष व्यक्ति € 80 वाउचर के मूल्य के साथ सम्मानित किया गया है।

वाउचर एक विशेष देश के लिए उपलब्ध मूल्यवर्ग के लिए एक लुकअप तालिका के परिणामों के नीचे स्थित क्वेरी।

SELECT * FROM tblDenominationScheme WHERE CountryCode IN ('AT', 'US')

परिणाम:

No. | CountryCode  |   VoucherName | VoucherValue
-------------------------------------------------
1   | AT           |   €50 Shop A  |     50
2   | AT           |   €25 Shop A  |     25
3   | AT           |   €15 Shop A  |     15
4   | AT           |   €10 Shop A  |     10
5   | US           |   $50 Store B |     50
6   | US           |   $10 Store B |     10
7   | US           |   $5 Store B  |      5

मेरे वर्तमान एसक्यूएल नीचे के रूप में € 80 वाउचर के लिए आवश्यक वाउचर मूल्यवर्ग निर्धारित करने के लिए है:

   DECLARE @CountryCode1 VARCHAR(2) = 'AT'
   DECLARE @ChallengerID INT = 1172
   DECLARE @RoundedAmount1 INT = 80
   DECLARE @Vouchers INT
   DECLARE @AmountAwarded INT = 0

   SET @AmountAwarded = @RoundedAmount1

   DROP TABLE IF EXISTS #tempVoucher

   CREATE TABLE #tempVoucher
   (
          CountryCode VARCHAR(2),
          ChallengerID INT,
          AmountAwarded INT,
          Vouchers INT,
   )

   WHILE (@RoundedAmount1 > 0)
   BEGIN

          SET @Vouchers = 0

          SELECT TOP 1 @Vouchers = VoucherValue FROM tblDenominationScheme WHERE CountryCode = @CountryCode1 AND VoucherValue <= @RoundedAmount1 ORDER BY VoucherValue DESC

          IF (@Vouchers > 0)
          BEGIN
                 SET @RoundedAmount1 = @RoundedAmount1 - @Vouchers
          END
          ELSE
          BEGIN
                 SELECT TOP 1 @Vouchers = VoucherValue FROM tblDenominationScheme WHERE CountryCode = @CountryCode1 ORDER BY VoucherValue
                 SET @RoundedAmount1 = @RoundedAmount1 - @RoundedAmount1
          END

          INSERT INTO #tempVoucher VALUES (@CountryCode1,@ChallengerID, @AmountAwarded, @Vouchers)
   END

   SELECT * FROM #tempVoucher

ऊपर एसक्यूएल से परिणाम:

No. | CountryCode  | ChallengerID |   AmountAwarded | Vouchers
--------------------------------------------------------------
1   | AT           | 1172         |   80            |   50
2   | AT           | 1172         |   80            |   25
3   | AT           | 1172         |   80            |   10

नोट: AmountAwarded स्तंभ में मान सभी 3 पंक्तियों के लिए एक ही हो जाएगा। 3 पंक्तियों के लिए वाउचर कॉलम की राशि से 80 योग करना चाहिए।

ऊपर परिणाम, स्पष्ट रूप से सही नहीं है क्योंकि अगर आप वाउचर स्तंभ में मानों योग, तो यह आपको 85 जो 5 AmountAwarded से अधिक है देता है,

अपेक्षित परिणाम (या निकटतम कम से कम):

No. | CountryCode  | ChallengerID |   AmountAwarded | Vouchers
--------------------------------------------------------------
1   | AT           | 1172         |   80            |   50
2   | AT           | 1172         |   80            |   10
3   | AT           | 1172         |   80            |   10
4   | AT           | 1172         |   80            |   10

किसी को भी मदद करने में सक्षम?

02/12/2019 को 23:58
का स्रोत उपयोगकर्ता
अन्य भाषाओं में...                            


3 जवाब

वोट
1

यह एक महंगी क्वेरी हो सकता है, लेकिन आप विभिन्न विकल्पों आप अपेक्षित परिणाम प्राप्त करने के लिए 7 वाउचर अप करने के लिए वितरित करने के लिए हो जाता है। लेकिन यह एक बड़ी राशि पढ़ता है की अगर पंक्तियों में वृद्धि या वाउचर की राशि अधिक से अधिक हो सकता है उत्पन्न होगा।

  DECLARE @CountryCode1 VARCHAR(2) = 'AT'
   DECLARE @RoundedAmount1 INT = 80;

WITH cteDenominations AS(
    SELECT No, VoucherValue 
    FROM tblDenominationScheme 
    WHERE CountryCode = @CountryCode1
    UNION ALL
    SELECT 10000, 0
),
ctePermutations AS(
    SELECT a.No             AS a_No, 
           a.VoucherValue   AS a_Value, 
           b.No             AS b_No, 
           b.VoucherValue   AS b_Value,
           c.No             AS c_No, 
           c.VoucherValue   AS c_Value,
           d.No             AS d_No, 
           d.VoucherValue   AS d_Value,
           e.No             AS e_No, 
           e.VoucherValue   AS e_Value,
           f.No             AS f_No, 
           f.VoucherValue   AS f_Value,
           g.No             AS g_No, 
           g.VoucherValue   AS g_Value,
        ROW_NUMBER() OVER(ORDER BY a.No, b.No, c.No, d.No) Permutation
    FROM cteDenominations a
    JOIN cteDenominations b ON a.VoucherValue >= b.VoucherValue
    JOIN cteDenominations c ON b.VoucherValue >= c.VoucherValue
    JOIN cteDenominations d ON c.VoucherValue >= d.VoucherValue
    JOIN cteDenominations e ON d.VoucherValue >= e.VoucherValue
    JOIN cteDenominations f ON e.VoucherValue >= f.VoucherValue
    JOIN cteDenominations g ON f.VoucherValue >= g.VoucherValue
    WHERE @RoundedAmount1 = a.VoucherValue 
                          + b.VoucherValue 
                          + c.VoucherValue 
                          + d.VoucherValue 
                          + e.VoucherValue 
                          + f.VoucherValue 
                          + g.VoucherValue 
)
SELECT Permutation,
    u.No,
    u.VoucherValue
FROM ctePermutations
CROSS APPLY (VALUES(a_No, a_Value),
                   (b_No, b_Value),
                   (c_No, c_Value),
                   (d_No, d_Value),
                   (e_No, e_Value),
                   (f_No, f_Value),
                   (g_No, g_Value))u(No, VoucherValue)
WHERE VoucherValue > 0
AND   Permutation = 1 --Remove this to get all possibilities
;
03/12/2019 को 01:05
का स्रोत उपयोगकर्ता

वोट
1

लगता है कि आप एक समीकरण को हल करने की जरूरत है की तरह है:

80 = n1*v1 + k2*n2...

जहां v1,v2 ...मान जो आप डेटाबेस में स्टोर कर रहे हैं और अगर आप खोजने की जरूरत है n1, n2 ...जो कर रहे हैं में, {0, N} कोई रास्ता नहीं कैसे एसक्यूएल में इसे लागू करने नहीं है। छोड़कर - सभी संभव मूल्यों पर, लेकिन यह समझदारी भरा तरीका नहीं है।

: इसके अलावा, इस जानकारी को देखने के https://math.stackexchange.com/questions/431367/solving-a-first-order-diophantine-equation-with-many-terms

03/12/2019 को 01:08
का स्रोत उपयोगकर्ता

वोट
0

तर्क

  1. सबसे बड़ी राशि का पता लगाएं (है कि कम से कम या शुरू करने राशि के बराबर) 1 संप्रदाय के वाउचर बना सकते हैं।
  2. शेष राशि प्राप्त करने के लिए शुरू करने से इस मूल्य घटाएँ,
  3. सबसे बड़ी राशि का पता लगाएं (है कि कम से कम या शेष के बराबर) 1 के वाउचर के एक नंबर छोटे संप्रदाय बना सकते हैं।
  4. पिछले शेष से इस मूल्य घटाना।
  5. चरण 3 पर वापस जाएँ

विशेषताएं:

  • कई संभालती सबसे अच्छा संयोजन।
  • संयोजन की छोटी संख्या की खोज कर रहे हैं।
  • अपने लैपटॉप पर: 100 रन 3 सेकंड के बारे में ले

टिप्पणियाँ

प्रदर्शन के उत्पादन में बचत द्वारा सुधार किया जा सकता है VoucherCombinationsएक मेज चर के लिए और फिर बाद में सीटीई में इसका उपयोग करने।

कोड:

DECLARE @Vouchers TABLE( CountryCode CHAR( 2 ), VoucherValue DECIMAL( 10, 2 ))
INSERT INTO @Vouchers VALUES( 'AT', 50 ), ( 'AT', 40 ), ( 'AT', 25 ), ( 'AT', 20 ), ( 'AT', 15 ), ( 'AT', 10 ), ( 'US', 50 ), ( 'US', 10 ), ( 'US', 5 );

-- Small number table
-- Limits maximum count of Vouchers of a given denomination.
DECLARE @Numbers TABLE( Num INT )
INSERT INTO @Numbers VALUES( 1 ), ( 2 ), ( 3 ), ( 4 ), ( 5 ), ( 6 ), ( 7 ), ( 8 ), ( 9 ), ( 10 )

DECLARE @TargetAmount DECIMAL( 10, 2 ) = 60;
DECLARE @CountryCode CHAR( 2 ) = 'AT';

;WITH VoucherCombinations
AS (
    -- Anchor
    SELECT ROW_NUMBER() OVER( ORDER BY VoucherValue DESC ) AS ParentGroupID,
        ROW_NUMBER() OVER( ORDER BY VoucherValue DESC ) AS SubGroupID,
        1 AS IterationID,
        VoucherValue, Num AS VoucherCumulativeCount,
        CAST( VoucherValue * Num AS DECIMAL( 10, 2 )) AS TotalDenominationValue,
        CAST( @TargetAmount - ( VoucherValue * Num ) AS DECIMAL( 10, 2 )) AS Remainder
    FROM @Vouchers
        -- Find the largest amount a given Voucher denomination can produce that is less than or equal to @TargetAmount
        INNER JOIN @Numbers ON ( VoucherValue * Num ) <= @TargetAmount AND @TargetAmount - ( VoucherValue * Num ) < VoucherValue
    WHERE CountryCode = @CountryCode
    UNION ALL
    -- Recursive query
    SELECT SubGroupID,
        SubGroupID * 10 + ROW_NUMBER() OVER( ORDER BY V.VoucherValue DESC ) AS SubGroupID,
        IterationID + 1,
        V.VoucherValue, VoucherCumulativeCount + N.Num AS VoucherCount,
        CAST( V.VoucherValue * N.Num AS DECIMAL( 10, 2 )) AS TotalDenominationValue,
        CAST( Remainder - ( V.VoucherValue * N.Num ) AS DECIMAL( 10, 2 )) AS Remainder
    FROM VoucherCombinations AS VP
        -- For each denomination look at the smaller denominations
        INNER JOIN @Vouchers AS V ON VP.VoucherValue > V.VoucherValue
            INNER JOIN @Numbers AS N ON V.VoucherValue * N.Num <= Remainder AND Remainder - ( V.VoucherValue * N.Num ) < V.VoucherValue
    WHERE CountryCode = @CountryCode
),
-- Discard invalid combinations i.e. remainder is not 0
VoucherPoolValid AS(
    SELECT *, DENSE_RANK() OVER( ORDER BY VoucherCumulativeCount ASC ) AS BestCombos
    FROM VoucherCombinations
    WHERE Remainder = 0
),
-- Find best combinations i.e. smallest number of Vouchers; Note: logic supports having more than 1 best combination
VoucherPoolBestCombos AS(
    SELECT *, ROW_NUMBER() OVER( ORDER BY BestCombos ASC ) AS ComboID
    FROM VoucherPoolValid
    WHERE BestCombos = 1
),
-- Return all denominations for each combination
VoucherPoolAllDetails AS(
    SELECT *
    FROM VoucherPoolBestCombos
    UNION ALL
    SELECT Parent.*, BestCombos, ComboID
    FROM VoucherPoolAllDetails AS Child
        INNER JOIN VoucherCombinations AS Parent ON Child.ParentGroupID = Parent.SubGroupID
    WHERE Child.SubGroupID <> Child.ParentGroupID
)
SELECT * FROM VoucherPoolAllDetails
ORDER BY ComboID
03/12/2019 को 04:20
का स्रोत उपयोगकर्ता

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more