क्वेरी चुनौती: एक पंक्ति नहीं पंक्ति माप के आधार पर आकार की बाल्टियाँ बनाना


12

मैं आदेश के साथ ट्रकों की एक निश्चित संख्या को लोड करने के संदर्भ में समस्या का वर्णन करूंगा, यथासंभव समान रूप से।

इनपुट:

@TruckCount - the number of empty trucks to fill

एक सेट:

OrderId, 
OrderDetailId, 
OrderDetailSize, 
TruckId (initially null)

Ordersएक या अधिक से बना है OrderDetails

यहां चुनौती TruckIdप्रत्येक रिकॉर्ड को एक असाइन करना है।

एक भी आदेश ट्रकों में विभाजित नहीं किया जा सकता है।

ट्रकों को यथासंभव समान रूप से लोड किया जाना चाहिए sum(OrderDetailSize)

* समान रूप से: सबसे कम लोड किए गए ट्रक और सबसे अधिक लोड किए गए ट्रक के बीच सबसे छोटा प्राप्त डेल्टा। इस परिभाषा के अनुसार, 1,2,3 1,1,4 से अधिक समान रूप से वितरित है। यदि यह मदद करता है, तो आप सांख्यिकी एल्गोरिथ्म का दिखावा करें, यहां तक ​​कि ऊंचाई हिस्टोग्राम भी बनाते हैं।

अधिकतम ट्रक लोड के लिए कोई विचार नहीं किया गया है। ये मैजिक इलास्टिक ट्रक हैं। हालांकि ट्रकों की संख्या निर्धारित है।

एक स्पष्ट रूप से समाधान है जो चलने का है - राउंड रॉबिन ऑर्डर आवंटित करता है।

लेकिन क्या इसे सेट आधारित तर्क के रूप में किया जा सकता है?

मेरी मुख्य रुचि SQL सर्वर 2014 या उसके बाद के लिए है। लेकिन अन्य प्लेटफार्मों के लिए सेट आधारित समाधान भी दिलचस्प हो सकते हैं।

ऐसा लगता है कि इट्ज़िक बेन-गण क्षेत्र :)

मेरा वास्तविक विश्व अनुप्रयोग तार्किक CPU की संख्या से मेल खाने के लिए कई बकेट में एक प्रोसेसिंग वर्कलोड वितरित कर रहा है। इसलिए प्रत्येक बाल्टी का अधिकतम आकार नहीं होता है। आँकड़े अद्यतन, विशेष रूप से। मैंने सोचा था कि चुनौती को तैयार करने के तरीके के रूप में ट्रकों में समस्या को खत्म करना अधिक मजेदार था।

CREATE TABLE #OrderDetail (
OrderId int NOT NULL,
OrderDetailId int NOT NULL PRIMARY KEY,
OrderDetailSize tinyint NOT NULL,
TruckId tinyint NULL)

-- Sample Data

INSERT #OrderDetail (OrderId, OrderDetailId, OrderDetailSize)
VALUES
(1  ,100    ,75 ),
(2  ,101    ,5  ),
(2  ,102    ,5  ),
(2  ,103    ,5  ),
(2  ,104    ,5  ),
(2  ,105    ,5  ),
(3  ,106    ,100),
(4  ,107    ,1  ),
(5  ,108    ,11 ),
(6  ,109    ,21 ),
(7  ,110    ,49 ),
(8  ,111    ,25 ),
(8  ,112    ,25 ),
(9  ,113    ,40 ),
(10 ,114    ,49 ),
(11 ,115    ,10 ),
(11 ,116    ,10 ),
(12 ,117    ,15 ),
(13 ,118    ,18 ),
(14 ,119    ,26 )
--> YOUR SOLUTION HERE

-- After assigning Trucks, Measure delta between most and least loaded trucks.
-- Zero is perfect score, however the challenge is a set based solution that will scale, and produce good results, rather
-- than iterative solution that will produce perfect results by exploring every possibility.

SELECT max(TruckOrderDetailSize) - MIN(TruckOrderDetailSize) AS TruckMinMaxDelta
FROM 
(SELECT SUM(OrderDetailSize) AS TruckOrderDetailSize FROM #OrderDetail GROUP BY TruckId) AS Truck


DROP TABLE #OrderDetail


1
ह्यूगो कोर्नेलिस ने इस पर एक अच्छा काम किया है।
एरिक डार्लिंग

क्या सभी OrderDetailSize मान किसी दिए गए OrderId के लिए समान होंगे या यह कि आपके नमूना डेटा में सिर्फ सह-घटना है?
Youcantryreachingme

@youcantryreachingme आह, अच्छा स्थान ... नहीं है कि नमूना डेटा में सिर्फ सह-घटना है।
पॉल होम्स

जवाबों:


5

मेरा पहला विचार था

select
    <best solution>
from
    <all possible combinations>

"सबसे अच्छा समाधान" भाग को प्रश्न में परिभाषित किया गया है - सबसे भरी हुई और कम से कम भरी हुई ट्रकों के बीच सबसे छोटा अंतर। अन्य बिट - सभी संयोजन - मुझे विचार के लिए विराम देते हैं।

ऐसी स्थिति पर विचार करें जहां हमारे पास तीन ऑर्डर ए, बी और सी और तीन ट्रक हैं। संभावनाएं हैं

Truck 1 Truck 2 Truck 3
------- ------- -------
A       B       C
A       C       B
B       A       C
B       C       A
C       A       B
C       B       A
AB      C       -
AB      -       C
C       AB      -
-       AB      C
C       -       AB
-       C       AB
AC      B       -
AC      -       B
B       AC      -
-       AC      B
B       -       AC
-       B       AC
BC      A       -
BC      -       A
A       BC      -
-       BC      A
A       -       BC
-       A       BC
ABC     -       -
-       ABC     -
-       -       ABC

Table A: all permutations.

इनमें से कई सममित हैं। उदाहरण के लिए, पहली छह पंक्तियाँ, केवल उसी क्रम में भिन्न होती हैं, जिसमें प्रत्येक क्रम को ट्रक में रखा जाता है। चूँकि ट्रक फंगस वाले हैं, इन व्यवस्थाओं के परिणाम समान होंगे। मैं अभी के लिए इसे अनदेखा करूंगा।

क्रमपरिवर्तन और संयोजन के निर्माण के लिए ज्ञात प्रश्न हैं। हालांकि, ये एक ही बाल्टी के भीतर व्यवस्था का उत्पादन करेंगे। इस समस्या के लिए मुझे कई बाल्टियों की व्यवस्था की आवश्यकता है।

मानक "सभी संयोजनों" क्वेरी से आउटपुट को देखते हुए

;with Numbers as
(
    select n = 1
    union
    select 2
    union
    select 3
)
select
    a.n,
    b.n,
    c.n
from Numbers as a
cross join Numbers as b
cross join Numbers as c
order by 1, 2, 3;


  n   n   n
--- --- ---
  1   1   1
  1   1   2
  1   1   3
  1   2   1
 <snip>
  3   2   3
  3   3   1
  3   3   2
  3   3   3

Table B: cross join of three values.

मैंने कहा कि परिणाम तालिका ए के समान पैटर्न का गठन करते हैं। प्रत्येक कॉलम को ऑर्डर 1 मानने की अनुमानी छलांग लगाकर , मानों को कहने के लिए कि कौन सा ट्रक उस ऑर्डर को रखेगा, और ट्रकों के भीतर ऑर्डर की व्यवस्था करने के लिए एक पंक्ति । फिर क्वेरी बन जाती है

select
    Arrangement             = ROW_NUMBER() over(order by (select null)),
    First_order_goes_in     = a.TruckNumber,
    Second_order_goes_in    = b.TruckNumber,
    Third_order_goes_in     = c.TruckNumber
from Trucks a   -- aka Numbers in Table B
cross join Trucks b
cross join Trucks c

Arrangement First_order_goes_in Second_order_goes_in Third_order_goes_in
----------- ------------------- -------------------- -------------------
          1                   1                    1                   1
          2                   1                    1                   2
          3                   1                    1                   3
          4                   1                    2                   1
  <snip>

Query C: Orders in trucks.

उदाहरण के डेटा में चौदह आदेशों को शामिल करने के लिए इसका विस्तार करना, और हमारे द्वारा प्राप्त नामों को सरल बनाना:

;with Trucks as
(
    select * 
    from (values (1), (2), (3)) as T(TruckNumber)
)
select
    arrangement = ROW_NUMBER() over(order by (select null)),
    First       = a.TruckNumber,
    Second      = b.TruckNumber,
    Third       = c.TruckNumber,
    Fourth      = d.TruckNumber,
    Fifth       = e.TruckNumber,
    Sixth       = f.TruckNumber,
    Seventh     = g.TruckNumber,
    Eigth       = h.TruckNumber,
    Ninth       = i.TruckNumber,
    Tenth       = j.TruckNumber,
    Eleventh    = k.TruckNumber,
    Twelth      = l.TruckNumber,
    Thirteenth  = m.TruckNumber,
    Fourteenth  = n.TruckNumber
into #Arrangements
from Trucks a
cross join Trucks b
cross join Trucks c
cross join Trucks d
cross join Trucks e
cross join Trucks f
cross join Trucks g
cross join Trucks h
cross join Trucks i
cross join Trucks j
cross join Trucks k
cross join Trucks l
cross join Trucks m
cross join Trucks n;

Query D: Orders spread over trucks.

मैं सुविधा के लिए अस्थायी तालिकाओं में मध्यवर्ती परिणाम पकड़ना चुनता हूं।

यदि डेटा पहले UNPIVOTED है तो बाद के चरण बहुत आसान होंगे।

select
    Arrangement,
    TruckNumber,
    ItemNumber  = case NewColumn
                    when 'First'        then 1
                    when 'Second'       then 2
                    when 'Third'        then 3
                    when 'Fourth'       then 4
                    when 'Fifth'        then 5
                    when 'Sixth'        then 6
                    when 'Seventh'      then 7
                    when 'Eigth'        then 8
                    when 'Ninth'        then 9
                    when 'Tenth'        then 10
                    when 'Eleventh'     then 11
                    when 'Twelth'       then 12
                    when 'Thirteenth'   then 13
                    when 'Fourteenth'   then 14
                    else -1
                end
into #FilledTrucks
from #Arrangements
unpivot
(
    TruckNumber
    for NewColumn IN 
    (
        First,
        Second,
        Third,
        Fourth,
        Fifth,
        Sixth,
        Seventh,
        Eigth,
        Ninth,
        Tenth,
        Eleventh,
        Twelth,
        Thirteenth,
        Fourteenth
    )
) as q;

Query E: Filled trucks, unpivoted.

आदेश तालिका में शामिल होने से वज़न का परिचय दिया जा सकता है।

select
    ft.arrangement,
    ft.TruckNumber,
    TruckWeight = sum(i.Size)
into #TruckWeights
from #FilledTrucks as ft
inner join #Order as i
    on i.OrderId = ft.ItemNumber
group by
    ft.arrangement,
    ft.TruckNumber;

Query F: truck weights

इस सवाल का जवाब अब उस व्यवस्था (ओं) को ढूंढकर दिया जा सकता है, जिनमें सबसे अधिक लोड वाले और कम-लोडेड ट्रकों के बीच सबसे छोटा अंतर है

select
    Arrangement,
    LightestTruck   = MIN(TruckWeight),
    HeaviestTruck   = MAX(TruckWeight),
    Delta           = MAX(TruckWeight) - MIN(TruckWeight)
from #TruckWeights
group by
    arrangement
order by
    4 ASC;

Query G: most balanced arrangements

विचार-विमर्श

इसके साथ बहुत सारी समस्याएं हैं। सबसे पहले यह एक जानवर-बल एल्गोरिथ्म है। ट्रकों और आदेशों की संख्या में काम करने वाली तालिकाओं में पंक्तियों की संख्या घातीय है। # व्यवस्थाओं में पंक्तियों की संख्या (ट्रकों की संख्या) ^ (आदेशों की संख्या) है। यह अच्छा पैमाना नहीं होगा।

दूसरा यह है कि एसक्यूएल प्रश्नों में उनके द्वारा अंतर्निहित आदेशों की संख्या होती है। इसका एकमात्र तरीका गतिशील एसक्यूएल का उपयोग करना है, जिसकी अपनी समस्याएं हैं। यदि आदेशों की संख्या हजारों में है, तो उत्पन्न SQL बहुत लंबा होने पर एक समय आ सकता है।

तीसरा है व्यवस्थाओं में अतिरेक। यह मध्यवर्ती तालिकाओं को क्रमिक रूप से बढ़ाता है।

चौथा, # व्यवस्था में कई पंक्तियाँ एक या एक से अधिक ट्रकों को खाली छोड़ देती हैं। यह संभवतः इष्टतम विन्यास नहीं हो सकता है। रचना पर इन पंक्तियों को फ़िल्टर करना आसान होगा। मैंने कोड को सरल और केंद्रित रखने के लिए ऐसा नहीं करने के लिए चुना है।

ऊपर की तरफ यह नकारात्मक भार को संभालता है, क्या आपके उद्यम को कभी भी भरे हुए हीलियम के बलबूते को शुरू करना चाहिए!

विचार

अगर ट्रकों और आदेशों की सूची से सीधे #FilledTrucks को आबाद करने का एक तरीका था, तो मुझे लगता है कि इन चिंताओं में से सबसे अधिक प्रबंधनीय होगा। अफसोस की बात यह है कि मेरी बाधा उस बाधा पर ठोकर खा गई। मेरी आशा है कि भविष्य में कुछ योगदानकर्ता उस आपूर्ति को करने में सक्षम हो सकते हैं जिसने मुझे हटा दिया है।




1 आप कहते हैं कि एक ऑर्डर के लिए सभी आइटम एक ही ट्रक पर होने चाहिए। इसका मतलब है कि असाइनमेंट का परमाणु ऑर्डर है, ऑर्डरडेटेल नहीं। मैंने आपके परीक्षण डेटा से इस प्रकार उत्पन्न किया है:

select
    OrderId,
    Size = sum(OrderDetailSize)
into #Order
from #OrderDetail
group by OrderId;

इससे कोई फर्क नहीं पड़ता, हालांकि, चाहे हम आइटम को प्रश्न 'ऑर्डर' या 'ऑर्डरडेटेल' में लेबल करते हैं, समाधान एक ही रहता है।


4

आपकी वास्तविक विश्व आवश्यकता को देखते हुए (जो मैं मान रहा हूँ कि आपके कार्यभार को सस्पस के एक समूह में संतुलित करने के प्रयास में है) ...

क्या कोई कारण है कि आपको विशिष्ट बाल्टियों / सीपीस के लिए प्रक्रियाओं को पूर्व-असाइन करने की आवश्यकता है? [अपनी वास्तविक आवश्यकताओं को समझने की कोशिश कर रहा है ]

'आँकड़े अपडेट' के अपने उदाहरण के लिए, आप कैसे जानते हैं कि किसी विशेष ऑपरेशन में कितना समय लगेगा? यदि किसी दिए गए ऑपरेशन में अप्रत्याशित देरी हो जाती है (जैसे, टेबल-इंडेक्स से अधिक-नियोजित / अत्यधिक विखंडन, लंबे समय तक चलने वाला उपयोगकर्ता txn एक 'आँकड़े अद्यतन' ऑपरेशन को अवरुद्ध करता है)?


लोड संतुलन उद्देश्यों के लिए मैं आम तौर पर कार्यों की सूची (उदाहरण के लिए, तालिका की सूची आँकड़े अद्यतन करने के लिए) और एक (अस्थायी / खरोंच) तालिका में जगह कहा।

तालिका की संरचना को आपकी आवश्यकताओं के अनुसार संशोधित किया जा सकता है, जैसे:

create table tasks
(id        int             -- auto-increment?

,target    varchar(1000)   -- 'schema.table' to have stats updated, or perhaps ...
,command   varchar(1000)   -- actual command to be run, eg, 'update stats schema.table ... <options>'

,priority  int             -- provide means of ordering operations, eg, maybe you know some tasks will run really long so you want to kick them off first
,thread    int             -- identifier for parent process?
,start     datetime        -- default to NULL
,end       datetime        -- default to NULL
)

इसके बाद, मैं वास्तविक 'आँकड़े अद्यतनों' के संचालन के लिए समवर्ती प्रक्रियाओं की X संख्या को किक करता हूँ, प्रत्येक प्रक्रिया निम्नलिखित प्रदर्शन करती है:

  • tasksटेबल पर अनन्य लॉक लगाएं (यह सुनिश्चित करता है कि कोई भी कार्य एक से अधिक प्रक्रियाओं द्वारा नहीं किया जाता है; अपेक्षाकृत अल्पकालिक लॉक होना चाहिए)
  • 'पहली' पंक्ति खोजें, जहां start = NULL('पहले' आपके द्वारा निर्धारित किया जाएगा, उदाहरण के लिए, क्रम से priority?)
  • अद्यतन पंक्ति सेट start = getdate(), thread = <process_number>
  • अद्यतन करें (और अनन्य लॉक जारी करें)
  • idऔर target/commandमूल्यों पर ध्यान दें
  • target(वैकल्पिक रूप से, चलाने के खिलाफ command) वांछित ऑपरेशन करें और जब किया जाए ...
  • के tasksसाथ अद्यतन करेंend = getdate() where id = <id>
  • कोई और कार्य करने के लिए ऊपर दोहराएं

उपरोक्त डिज़ाइन के साथ मुझे अब एक गतिशील (अधिकतर) संतुलित संचालन मिला है।

टिप्पणियाँ:

  • मैं किसी प्रकार की प्राथमिकता देने की विधि प्रदान करने का प्रयास करता हूं ताकि मैं आगे चल रहे कार्यों को आगे बढ़ा सकूं; जबकि कुछ प्रक्रियाएं लंबे समय तक चलने वाले कार्यों पर काम कर रही हैं, अन्य प्रक्रियाएं कम चलने वाले कार्यों की सूची के माध्यम से मंथन कर सकती हैं
  • यदि कोई प्रक्रिया अनियोजित विलंब में चलती है (जैसे, लंबे समय तक चलने वाला, उपयोगकर्ता txn को अवरुद्ध करना), तो अन्य प्रक्रियाएं 'अगले उपलब्ध' ऑपरेशन को जारी रखने के लिए 'सुस्त' उठा सकती हैं। tasks
  • tasksतालिका का डिज़ाइन अन्य लाभों के लिए प्रदान करना चाहिए, उदाहरण के लिए, रन समय का इतिहास जिसे आप भविष्य के संदर्भ के लिए संग्रहित कर सकते हैं, रन टाइम का इतिहास जो प्राथमिकताओं को संशोधित करने के लिए इस्तेमाल किया जा सकता है, वर्तमान संचालन की स्थिति प्रदान कर सकता है, आदि।
  • जबकि 'एक्सक्लूसिव लॉक' tasksथोड़ा अधिक लग सकता है, ध्यान रखें कि हमें एक ही समय में एक नया कार्य प्राप्त करने के लिए 2 (या अधिक) प्रक्रियाओं के संभावित मुद्दे की योजना बनानी होगी , इसलिए हमें एक कार्य की गारंटी देने की आवश्यकता है केवल एक ही प्रक्रिया को सौंपा गया है (और हाँ, आप एक कॉम्बो 'अपडेट / चयन' कथन के साथ वही परिणाम प्राप्त कर सकते हैं - जो आपके RDBMS की SQL भाषा क्षमताओं पर निर्भर करता है); एक नया 'कार्य' प्राप्त करने का कदम त्वरित होना चाहिए, अर्थात, 'एक्सक्लूसिव लॉक' को अल्पकालिक होना चाहिए और वास्तव में, प्रक्रियाओं को tasksकाफी यादृच्छिक तरीके से मारना होगा ताकि थोड़ा भी अवरुद्ध हो जाए

व्यक्तिगत रूप से, मुझे इस tasksतालिका संचालित प्रक्रिया को लागू करने और बनाए रखने में थोड़ा आसान लगता है ... जैसा कि (आमतौर पर) कार्य / प्रक्रिया मैपिंग ... ymmv को पूर्व-असाइन करने की कोशिश करने की अधिक जटिल प्रक्रिया के विपरीत है।


जाहिर तौर पर आपके विश्वास के लिए उदाहरण है कि आप अपने ट्रकों को अगले आदेश के लिए वितरण / गोदाम में वापस नहीं जा सकते हैं, इसलिए आपको अपने ऑर्डर को विभिन्न ट्रकों (यूपीएस / फेडेक्स / आदि को ध्यान में रखते हुए) को पूर्व-असाइन करने की आवश्यकता है प्रसव के समय और गैस के उपयोग को कम करने के लिए वितरण मार्गों के आधार पर असाइन करें)।

हालाँकि, आपके वास्तविक विश्व उदाहरण ('आँकड़े अद्यतन') में ऐसा कोई कारण नहीं है कि कार्य / प्रक्रिया असाइनमेंट को गतिशील रूप से नहीं किया जा सकता है, इस तरह से कार्यभार को संतुलित करने का बेहतर मौका सुनिश्चित होता है (cpus के पार और कुल रन समय को कम करने के संदर्भ में) ।

ध्यान दें: मैं नियमित रूप से (आईटी) लोगों को वास्तव में कहा कार्यों को चलाने से पहले अपने कार्यों (लोड संतुलन के रूप में) के लिए पूर्व-असाइन करने की कोशिश कर रहा हूं, और हर मामले में उसे लेने के लिए पूर्व-असाइनमेंट प्रक्रिया को लगातार समाप्त करने के लिए समाप्त होता है। लगातार कार्य के मुद्दों (जैसे, तालिका / सूचकांक में विखंडन का स्तर, समवर्ती उपयोगकर्ता गतिविधि, आदि) पर विचार करना।


सबसे पहले, यदि हम तालिका के रूप में 'ऑर्डर' के बारे में सोचते हैं, और मेज पर एक विशिष्ट आंकड़े के रूप में 'ऑर्डरडेटेल' करते हैं, तो विभाजन न करने का कारण प्रतिस्पर्धी बाल्टियों के बीच लॉक वेट से बचना है। Traceflag 7471 को इस मुद्दे को खत्म करने के लिए डिज़ाइन किया गया है, लेकिन मेरे परीक्षण में मेरे पास अभी भी लॉकिंग मुद्दे थे।
पॉल होम्स

मैं मूल रूप से एक बहुत हल्के समाधान बनाने की उम्मीद है। एकवचन बहुस्तरीय एसक्यूएल ब्लॉक के रूप में बकेट बनाएं, और फिर स्वयं को नष्ट करने वाले एसक्यूएल एजेंट नौकरियों का उपयोग करके 'आग और भूल जाओ'। अर्थात कोई कतार प्रबंधन कार्य नहीं। हालाँकि, बाद में मैंने पाया कि मैं आसानी से प्रति आँकड़ों की मात्रा को माप नहीं सका - पंक्तियों की संख्या ने इसे नहीं काटा। वास्तव में आश्चर्य की बात नहीं है, यह देखते हुए कि rowcount एक तालिका से IO की राशि के लिए रैखिक रूप से मैप नहीं करता है, या वास्तव में स्टैटिक, अगले तक। तो हाँ, इस आवेदन के लिए, यह वास्तव में कुछ सक्रिय कतार प्रबंधन के अतिरिक्त के साथ आत्म संतुलन कर सकता है जैसा कि आप सुझाव देते हैं।
पॉल होम्स

आपकी पहली टिप्पणी के लिए ... हाँ, वहाँ अभी भी (स्पष्ट) आदेशों की बारीकियों पर निर्णय है ... और समसामयिक मुद्दों जैसे: कुछ कमांड समानांतर में चलाए जा सकते हैं और उनके संयुक्त डिस्क रीड्स, आदि से लाभ हो सकता है, लेकिन मुझे अभी भी एक मिल रहा है (कुछ हद तक हल्का) डायनेमिक कतार प्रबंधन प्री-असाइनिंग बकेट्स की तुलना में थोड़ा अधिक कुशल है :-) आपको काम करने के लिए उत्तरों / विचारों का एक अच्छा सेट मिला है ... एक समाधान के साथ आने के लिए बहुत मुश्किल नहीं होना चाहिए कुछ सभ्य लोड संतुलन।
markp-fuso

1

अपनी इच्छानुसार नंबर टेबल बनाएं और आबाद करें। यह केवल एक बार का निर्माण है।

 create table tblnumber(number int not null)

    insert into tblnumber (number)
    select ROW_NUMBER()over(order by a.number) from master..spt_values a
    , master..spt_values b

    CREATE unique clustered index CI_num on tblnumber(number)

बनाया गया ट्रक टेबल

CREATE TABLE #PaulWhiteTruck (
Truckid int NOT NULL)

insert into #PaulWhiteTruck
values(113),(203),(303)

declare @PaulTruckCount int
Select @PaulTruckCount= count(*) from #PaulWhiteTruck

CREATE TABLE #OrderDetail (
id int identity(1,1),
OrderId int NOT NULL,
OrderDetailId int NOT NULL PRIMARY KEY,
OrderDetailSize int NOT NULL,
TruckId int NULL
)

INSERT
#OrderDetail (OrderId, OrderDetailId, OrderDetailSize)
VALUES
(
1 ,100 ,75 ),(2 ,101 ,5 ),
(2 ,102 ,5 ),(2 ,103 ,5 ),
(2 ,104 ,5 ),(2 ,105 ,5 ),
(3 ,106 ,100),(4 ,107 ,1 ),
(5 ,108 ,11 ),(6 ,109 ,21 ),
(7 ,110 ,49 ),(8 ,111 ,25 ),
(8 ,112 ,25 ),(9 ,113 ,40 ),
(10 ,114 ,49 ),(11 ,115 ,10 ),
(11 ,116 ,10 ),(12 ,117 ,15 ),
(13 ,118 ,18 ),(14 ,119 ,26 )

मैंने एक OrderSummaryटेबल बनाई है

create table #orderSummary(id int identity(1,1),OrderId int ,TruckOrderSize int
,bit_value AS
CONVERT
(
integer,
POWER(2, id - 1)
)
PERSISTED UNIQUE CLUSTERED)
insert into #orderSummary
SELECT OrderId, SUM(OrderDetailSize) AS TruckOrderSize
FROM #OrderDetail GROUP BY OrderId

DECLARE @max integer =
POWER(2,
(
SELECT COUNT(*) FROM #orderSummary 
)
) - 1
declare @Delta int
select @Delta= max(TruckOrderSize)-min(TruckOrderSize)   from #orderSummary

कृपया मेरा डेल्टा मान जांचें और मुझे बताएं कि क्या यह गलत है

;WITH cte 
     AS (SELECT n.number, 
                c.* 
         FROM   dbo.tblnumber AS N 
                CROSS apply (SELECT s.orderid, 
                                    s.truckordersize 
                             FROM   #ordersummary AS s 
                             WHERE  n.number & s.bit_value = s.bit_value) c 
         WHERE  N.number BETWEEN 1 AND @max), 
     cte1 
     AS (SELECT c.number, 
                Sum(truckordersize) SumSize 
         FROM   cte c 
         GROUP  BY c.number 
        --HAVING sum(TruckOrderSize) between(@Delta-25) and (@Delta+25) 
        ) 
SELECT c1.*, 
       c.orderid 
FROM   cte1 c1 
       INNER JOIN cte c 
               ON c1.number = c.number 
ORDER  BY sumsize 

DROP TABLE #orderdetail 

DROP TABLE #ordersummary 

DROP TABLE #paulwhitetruck 

आप सीटीई 1 के परिणाम की जांच कर सकते हैं, यह सब संभव है Permutation and Combination of order along with their size

अगर मेरा दृष्टिकोण यहां तक ​​सही है, तो मुझे किसी की मदद की जरूरत है।

लंबित कार्य:

फ़िल्टर और CTE13 भाग ( Truck count) का परिणाम ऐसा है जो Orderidप्रत्येक समूह के बीच अद्वितीय है और प्रत्येक भाग T ruckOrderSizeडेल्टा के पास है।


मेरा नवीनतम उत्तर जांचें। पोस्ट करते समय एक प्रश्न याद रखें, किसी ने भी मेरी गलती नहीं बताई। चस्पा पेस्ट और चलाएं
कुमार हर्ष 27'18
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.