sql - APEX का उपयोग कर एक गतिशील मैट्रिक्स रिपोर्ट को लागू करने के सर्वोत्तम तरीके क्या हैं?




oracle plsql report oracle-apex (4)

ओरेकल एप्लिकेशन एक्सप्रेस रूपरेखा का उपयोग करके मुझे यह काम पूरा करना होगा।

मान लें कि हमारे पास ऐसी कोई क्वेरी है:

select   
  col1,  
  col2,  
  val1,  
  val2,  
  val3,  
  val4,  
  val5,  
  val6,  
  val7,  
  val8,  
  val9,  
  val10,  
  val11  
from table(mega_function(city => ?, format => ?, percent => ?, days => ?));

और यह क्वेरी इस तरह कुछ देता है (सीएसवी प्रारूप में दिखाया गया है):

col1;col2;val1;val2;val3;val4;val5;val6;val7;val8;val9;val10;val11
S2;C1;32000;120;"15:38:28";1450;120;1500;1200;31000;120;32600;300
S1;C1;28700;120;"15:35:01";150;120;1500;1800;2700;60;28900;120
S1;C2;27000;240;"14:44:23";0;1500;240;1200;25500;60;null;null

इसे सरल बनाने के लिए, एक पाइपलाइन फ़ंक्शन पर क्वेरी के आधार जो कुछ मापदंडों को लेता है और पहले दो कॉलम col1;col2 2 के मूल्यों के विभिन्न युग्म के लिए कुछ सेट मान देता है।

मुझे जो लागू करने की आवश्यकता है वह एक मैट्रिक्स रिपोर्ट है, जहां col2 मान रिपोर्ट की पंक्तियों और col2 के कॉलम के रूप में कॉलम के रूप में col2 किया जाता है। चौराहे पर ऐसी कोशिकाएं होती हैं जो जोड़े के लिए मूल्यों का सेट होती हैं जिनमें कुछ स्वरूपण और शैलियां लागू होती हैं। इसके लिए भी क्या ज़रूरत है - पंक्तियों के आधार पर छंटनी है (जिसे कॉलम 'val1' के मानों के आधार पर कॉलम चाहिए)।

या यदि हम उपरोक्त आवश्यकताओं को एक मॉकअप पर दिखाते हैं:

तो सवाल यह है कि कुछ बातचीत और कस्टम शैलियों के साथ ऐसी मैट्रिक्स रिपोर्ट को लागू करने के लिए सबसे अच्छी पद्धतियां क्या हैं?

मैंने पहले से ही इसमें देखने की कोशिश की है:

  • इंटरैक्टिव रिपोर्ट पिवट कार्यक्षमता ( https://docs.oracle.com/cd/E71588_01/AEEUG/managing-pivot-reports.htm#AEEUG29137 ) - अनुकूलन का अभाव है, कई मानों के साथ बुरी तरह से काम करता है, खासकर जब वे नंबर न हों
  • फ़ंक्शन के आधार पर क्लासिक रिपोर्ट - मैंने पीएल / एसक्यूएल फ़ंक्शन कार्यान्वित किया है जो डायनामिक PIVOT एसक्यूएल क्वेरी को लौटाता है, रिपोर्ट के गुणों में, Use Generic Column Names Yes सेट करें (केवल क्रम में क्वेरी को पार्स करने के लिए) और रिपोर्ट के शीर्षकों के लिए मैंने एक अन्य पीएल / एसक्यूएल फ़ंक्शन का इस्तेमाल किया है, जो प्रारूप heading1:headning2:...:headingN में एक स्ट्रिंग उत्पन्न करता है। समाधान का काम करता है (आप इसे यहां जांच सकते हैं - https://apex.oracle.com/pls/apex/f?p=1328328 ), लेकिन मुझे रिपोर्ट को गतिशील रूप से प्रत्येक को ताज़ा करना होगा, हम कहते हैं, 5 सेकंड और यह प्रदर्शन के मामले में चूसना होगा (गतिशील एसक्यूएल हमेशा बुरा नहीं है और अगर हम निष्पादन योजनाओं के बारे में बात करते हैं तो यह संभव नहीं है)। इसके अलावा यह समाधान भी फिट नहीं है, क्योंकि हेडिंग डेटा के साथ घनिष्ठ नहीं होते हैं (वास्तव में मैंने order by col1 1 order by col1 में पीएल / एसक्यूएल दोनों कार्यों में उनके स्थान पर हेडिंग करने के लिए order by col1 ) और मैं नहीं जानता कि कैसे पंक्तियां बनाने के लिए यहां छांटने योग्य
  • पीएल / एसक्यूएल डायनेमिक सामग्री क्षेत्र - मैंने यहाँ कुछ कोड करने की कोशिश नहीं की है, लेकिन मुझे पता है कि यहां केवल एचटीपी पैकेज और एपेक्स एपीआई का उपयोग करने के लिए कुछ भी करना संभव है। मुश्किल बात यह है कि यह समाधान बहुत जटिल है, मुझे 'खरोंच से' रिपोर्ट के सभी तर्क को लागू करने की आवश्यकता होगी और मेरा मानना ​​है कि काम में सफल होने के लिए एक बेहतर और आसान तरीका है, जिसे मुझे नहीं पता।

Answers

तुम सही हो। मैंने आपके सुझावों की मेरी शुरुआती समझ के आधार पर केवल एक राय दी है .. अब जब मैंने पढ़ा है कि और अधिक ध्यान से, मैंने अपना दिमाग बदला क्योंकि मैंने महसूस किया कि यह आपके लिए मुश्किल मैट्रिक्स नहीं है .. वास्तव में मेरे पास बहुत से लोग हैं ।

मुझे सबसे अच्छा प्रथाओं के बारे में पता नहीं है लेकिन मैं आपके साथ साझा कर सकता हूं कि मैंने इसी प्रकार की आवश्यकताओं के साथ क्या किया है:

मैट्रिक्स आधारित रिपोर्टों के लिए मैं क्लासिक रिपोर्ट्स पसंद करता हूं, मैं शीर्ष लेख अनुभाग पर अपने फ़िल्टरिंग मापदंड (केवल आपके नकली में) डालता हूं और उपयोगकर्ता चयन के आधार पर जानकारी को बहुत अच्छी तरह से बदलता है इसी तरह मैं फ़िल्टरिंग और सॉर्टिंग को संभालता हूं।

अपनी आवश्यकताओं के साथ सबसे कठिन हिस्सा (आईएमओ) है उद्देश्यों को निर्यात करने के लिए कोशिकाओं की जांच .. आप अपनी क्वेरी में गतिशील रूप से एक टॉगल नियंत्रण को सक्षम करने में सक्षम होंगे और कुछ एजेएक्स के साथ आप चुने हुए लोगों को निर्यात के लिए पिकअप कर पाएंगे। ।


दुर्भाग्य से, इस प्रश्न में मैंने जो भी उल्लेख किया है, उनमें से कोई भी उन शर्तों की वजह से सभी आवश्यकताओं को पूरा नहीं करता है, जिसमें रिपोर्ट लाइव होगी:

  • डेटा गतिशील रूप से हर अद्यतन किया जाना चाहिए, हम कहते हैं, 5 सेकंड।
  • रिपोर्ट की स्थिति को डेटा अपडेट्स पर बचाया जाना चाहिए।
  • रिपोर्ट के कॉलम की संख्या चर (डेटा के साथ कॉलम की परिभाषा दी गई है), पंक्तियों की संख्या भी चर है। रिपोर्ट में सॉर्टिंग, पेजिंग और स्क्रोलिंग (एक्स और वाई) विकल्प होने चाहिए। क्लाइंट-साइड पर सभी सामान (सॉर्टिंग, इत्यादि) किए जाने चाहिए।
  • शैलियों और कस्टम सेल रेंडरिंग को तालिका के कक्षों पर लागू किया जाना चाहिए।
  • कोशिकाओं को क्लिक करने योग्य होना चाहिए (एक ईवेंट उत्पन्न करना चाहिए, जो इंटरसेप्टबल है)

मुझे एहसास हुआ कि ऐसे कार्य के लिए क्लासिक रिपोर्ट, इंटरेक्टिव रिपोर्ट या ग्रिड जैसे कुछ आउट-द-बॉक्स अपैक्स समाधानों का उपयोग करने के बजाय क्लाइंट-साइड पर डोम ऑन-फ्लाई को हेरफेर करना बेहतर होगा।

मैं इस दृष्टिकोण के लिए DataTables.js jQuery प्लगइन का इस्तेमाल किया। तकनीक का आकलन करने और कुछ बुनियादी जावास्क्रिप्ट सीखने के एक हफ्ते के बाद (जो मेरी प्राथमिक कौशल नहीं है), मेरे पास निम्न था:

एपेक्स आवेदन में मैंने एक अजाक्स कॉलबैक प्रक्रिया ( TEST_AJAX कहा जाता है) को लागू किया, यह पी एल / एसक्यूएल कोड चलाता है, जो SYS.HTP आउटपुट ( APEX_JSON या APEX_JSON पैकेजों का उपयोग करके) को SYS.HTP -ऑब्जेक्ट देता है। इसका स्रोत:

declare 
    l_temp sys_refcursor;
begin  
    open l_temp for go_pivot;
    APEX_JSON.open_object;
    APEX_JSON.open_array('columns');
    APEX_JSON.open_object;
    APEX_JSON.write('data', 'COL2');
    APEX_JSON.write('title', '/');
    APEX_JSON.close_object;
    for x in (select distinct col1 from test order by 1) loop
        APEX_JSON.open_object;
        APEX_JSON.write('data', upper(x.col1));
        APEX_JSON.write('title', x.col1);
        APEX_JSON.close_object;
    end loop;
    APEX_JSON.close_array;
    APEX_JSON.write('data', l_temp); 
    APEX_JSON.close_object;
end;

go_pivot फ़ंक्शन स्रोत:

create or replace function go_pivot return varchar2
  is
      l_query long := 'select col2';
  begin
      for x in (select distinct col1 from test order by col1)
      loop
          l_query := l_query ||
             replace(', min(decode(col1,''$X$'',v)) $X$',
                      '$X$',
                     x.col1);
     end loop;
     l_query := l_query || ' from test group by col2';
    return l_query;
 end;

फिर मैंने पृष्ठ पर एक स्टेटिक सामग्री क्षेत्र बनाया, जिसका स्रोत निम्न है:

<div id="datatable_test_container"></div>

मैंने सीएसएस और जेएस फाइलों को डाटा स्टैटिक फाइलों में डाटैटबल्स.जेस पर अपलोड किया है और उन्हें पेज प्रॉपर्टी में शामिल किया है। Function and Global Variable Declaration के पेज के JavaScript अनुभाग में मैंने यह जावास्क्रिप्ट कोड जोड़ा:

var $ = apex.jQuery;
var table;
var columns;
var rows;

//table initialization function
function table_init(json_data) {
    return $('#datatable_test').DataTable({
        //column defaults options
        columnDefs: [{
            "data": null,
            "defaultContent": "-",
            "targets": "_all"
        }],
        columns: json_data.columns,
        data: json_data.data,
        stateSave: true
    });
}
//function to asynchronously get data from APEX AJAX CALLBACK
//process and then to draw a table based on this data
function worker() {
    //run the process called TEST_JSON
    apex.server.process(
        "TEST_JSON", {}, {
            success: function(pData) {
                //on first run we need to initialize the table
                if (typeof table == 'undefined') {
                    //save current data for future use
                    columns = $.extend(true, [], pData.columns);
                    rows = $.extend(true, [], pData.data);
                    //generate empty html-table in the container
                    $('#datatable_test_container').append('<table id = "datatable_test" class = "display" cellspacing = "0" width = "100%" > < /table>');
                    //init the table
                    table = table_init(pData);
                    //when columns of the table changes we need to 
                    //reinitialize the table (DataTables require it due to architecture)
                } else if (JSON.stringify(columns) !=
                    JSON.stringify(pData.columns)) {
                    //save current data for future use
                    columns = $.extend(true, [], pData.columns);
                    rows = $.extend(true, [], pData.data);
                    //delete the table from DOM
                    table.destroy(true);
                    //generate empty html-table in the container
                    $('#datatable_test_container').append('<table id = "datatable_test" class = "display" cellspacing = "0" width = "100%" > < /table>');
                    //reinit the table
                    table = table_init(pData);
                }
                //if data changes, clear and re-draw the table
                else if (JSON.stringify(rows) != JSON.stringify(pData.data)) {
                    //save current data for future use
                    //we don't need to save the columns, they didn't change
                    rows = $.extend(true, [], pData.data);
                    //clear table, add rows from recieved JSON-object, re-
                    draw the table with new data
                    table.clear().rows.add(pData.data).draw(false);
                }
                //if nothing changes, we do nothing
            }
        }
    );
    //repeat the procedure in a second
    setTimeout(worker, 1000);
};

Execute when Page Loads मैं जोड़ा गया Execute when Page Loads लिए:

$(document).ready(function() {
    worker();
});

यह सब क्या करता है:

  1. स्थैतिक सामग्री क्षेत्र में स्थिर <div> एक खाली तालिका प्राप्त करता है जहां डेटाटाबेस निर्माता लागू किया जाता है।
  2. जावास्क्रिप्ट कोड अपने काम को अजाक्स कॉलबैक सर्वर प्रक्रिया को ट्रिगर करके शुरू कर देता है, और सफलता पर इस प्रक्रिया को वापस आती है।
  3. डेटाटाबेस कन्स्ट्रक्टर विभिन्न प्रकार के डेटा स्रोतों का समर्थन करता है, उदाहरण के लिए यह एक html-table पार्स कर सकता है या एजेक्स-कॉल कर सकता है, लेकिन मैं एपेक्स प्रक्रिया का उपयोग करने के लिए प्राथमिकता देता हूं और फिर जेएसएएन ऑब्जेक्ट पर तालिका का आधार देना चाहता हूं, जो इस प्रक्रिया को रिटर्न देता है।
  4. फिर स्क्रिप्ट देखता है यदि कॉलम में परिवर्तन होता है, तो तालिका को दस्तावेज़ से हटा दिया जाता है और नए डेटा का उपयोग करके पुन: आरंभीकृत किया जाता है, यदि केवल पंक्तियों में परिवर्तन होता है, तो इस डेटा के साथ तालिका फिर से तैयार की जाती है यदि डेटा में कुछ भी परिवर्तन नहीं होता है तो स्क्रिप्ट कुछ नहीं करता है
  5. इस प्रक्रिया को हर दूसरे को दोहराया जाता है

परिणामस्वरूप, सॉर्टिंग, पेजिंग, खोज, इवेंट हैंडलिंग और इतने पर जैसे विकल्पों के साथ, एक पूरी तरह से इंटरैक्टिव, गतिशील रीफ्रेश किया जा रहा है। और ये सब क्लाइंट-साइड पर सर्वर से अतिरिक्त प्रश्नों के बिना किया जाता है।

आप इस लाइव डेमो का उपयोग करके परिणाम की जांच कर सकते हैं (शीर्ष क्षेत्र डेटा टैब्स रिपोर्ट है, इसके नीचे स्रोत टैब पर एक संपादन योग्य इंटरैक्टिव ग्रिड है, परिवर्तन देखने के लिए, आप इंटरैक्टिव ग्रिड का उपयोग करके डेटा बदल सकते हैं)।

मुझे नहीं पता कि यह सबसे अच्छा तरीका है, लेकिन यह मेरी आवश्यकताओं को पूरा करता है

नवीनीकृत 05.09.2017: APEX_JSON अजाक्स कॉलबैक प्रक्रिया और go_pivot पीएल / एसक्यूएल समारोह की लिस्टिंग जोड़ा गया।


आपकी ज़रूरतों के आधार पर अपैक्स संभवत: सही उपकरण नहीं है, आप अंतहीन लाइब्रेरीज़ और जेक्टीय की क्षमताओं के द्वारा सीमित रहेंगे।

मैं एपेक्स पर इस तरह के आवेदन को विकसित करने का प्रयास नहीं करूँगा, मेरी राय में एपेक्स में दी गई तकनीक के लिए आवश्यकताओं को बहुत दूर है।

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


मैंने अपने TNSNAMES.ora फ़ाइल में " SID " को " SERVICE_NAME " में बदलकर इस समस्या को ठीक किया है।

कृपया देखें कि क्या आपका डीबी एसआईडी या SERVICE_NAME के ​​लिए पूछता है।

चियर्स





sql oracle plsql report oracle-apex