2012-12-05 34 views
7

में बहु-स्तंभ अनुक्रम बढ़ाना क्या कोई अंतर्निहित तरीका है (मेरा मतलब है, ट्रिगर्स और/या फ़ंक्शंस की आवश्यकता के बिना) एकाधिक कॉलम प्रति इंडेक्स बढ़ाने के लिए?PostgreSQL

तो प्रदर्शन के बाद:

INSERT INTO "table" 
    ("month", "desc") 
    VALUES 
    (1, 'One thing') 
, (1, 'Another thing') 
, (1, 'Last task of the month') 
, (2, 'Last task of the month') 
, (2, 'Last task of the month') 
, (3, 'First of third month') 

मेरे तालिका इस तरह खत्म हो जाएगा ("काम" कॉलम पर ध्यान दें):

month task desc 
1  1  One thing 
1  2  Another thing 
1  3  Last task of the month 
2  1  First of second month 
2  2  Second and last of second month 
3  1  First of third month 

उत्तर

12

आप (अपनी तालिका में simlpe SERIAL स्तंभ जोड़ सकते हैं कहीं भी होगी आपको चीजों के लिए आदेश दें) और फिर कुछ का उपयोग करें:

SELECT *, row_number() OVER (PARTITION BY month ORDER BY serial_column) 
FROM table 

यह आपको वें देगा ई परिणाम आप चाहते हैं।

आप पंक्तियों के आदेश की जरूरत नहीं है, तो आप की कोशिश कर सकते हैं:

SELECT *, row_number() OVER (PARTITION BY month) 
FROM table 

विवरण यहाँ: row_number() OVER(...)

युपीडी यह कैसे काम करता:

प्रकार SERIAL का एक कॉलम अनिवार्य रूप से एक है "ऑटो वृद्धि" क्षेत्र। यह स्वचालित रूप से एक अनुक्रम से एक मूल्य मिलता है। आप तालिका में पंक्तियां डालते हैं तो वे इस तरह दिखेगा:

| MONTH | SERIAL_COLUMN |      DESCRIPTION | 
----------------------------------------------------------- 
|  1 |    1 |      One thing | 
|  1 |    2 |     Another thing | 
|  1 |    3 |   Last task of the month | 
|  2 |    4 |   First of second month | 
|  2 |    5 | Second and last of second month | 
|  3 |    6 |   First of third month | 

मुख्य बात - हर अगले जोड़ा पंक्ति SERIAL_COLUMNअधिक से अधिक सभी पिछले पंक्तियों से का मूल्य है।

अगला। row_number() OVER (PARTITION BY month ORDER BY serial_column) करता है:

1) विभाजन सभी पंक्तियों समूहों में साथ बराबर month (PARTITION BY month)

2) के serial_column (ORDER BY serial_column)

3) मूल्य हर समूह में से उन्हें आदेश एक पंक्ति नंबर प्रदान करती है कदम 2 (`row_number() OVER)

से आदेश का उपयोग कर उत्पादन है:

| MONTH | SERIAL_COLUMN |      DESCRIPTION | ROW_NUMBER | 
------------------------------------------------------------------------ 
|  1 |    1 |      One thing |   1 | 
|  1 |    2 |     Another thing |   2 | 
|  1 |    3 |   Last task of the month |   3 | 
|  2 |    4 |   First of second month |   1 | 
|  2 |    5 | Second and last of second month |   2 | 
|  3 |    6 |   First of third month |   1 | 

row_number() के आउटपुट को बदलने के लिए आपको SERIAL_COLUMN में मानों को बदलने की आवश्यकता है। उदाहरण के इधर-उधर, First of second month एक से पहले Second and last of second month जगह ऐसे ही SERIAL_COLUMN के मूल्यों को बदल देगा:

UPDATE Table1 
SET serial_column = 5 
WHERE description = 'First of second month'; 

UPDATE Table1 
SET serial_column = 4 
WHERE description = 'Second and last of second month'; 

यह क्वेरी के उत्पादन में बदल जाएगा:

| MONTH | SERIAL_COLUMN |      DESCRIPTION | ROW_NUMBER | 
------------------------------------------------------------------------ 
|  1 |    1 |      One thing |   1 | 
|  1 |    2 |     Another thing |   2 | 
|  1 |    3 |   Last task of the month |   3 | 
|  2 |    4 | Second and last of second month |   1 | 
|  2 |    5 |   First of second month |   2 | 
|  3 |    6 |   First of third month |   1 | 

SERIAL_COLUMN में सटीक मान कोई फर्क नहीं है। उन्होंने केवल एक महीने में कार्यों पर एक आदेश निर्धारित किया।

मेरा SQLFiddle उदाहरण here है।

+0

में उपरोक्त कोड है। एक बहु-उपयोगकर्ता वातावरण में ** दौड़ की स्थिति ** बनाये बिना अंतराल संख्या को लागू करने के लिए * बहुत कठिन * है। आपको टेबल लॉक का भारी उपयोग करना होगा, जो प्रदर्शन के लिए एक असली डाउनर है। मेरा सुझाव है कि आप 'रैंक()' के बजाय 'row_number()' का उपयोग करें। परिणाम सहकर्मियों की अनुपस्थिति में समान है (इस मामले में), लेकिन 'row_number() 'सस्ता और अधिक उचित कार्य है। –

+0

@ErwinBrandstetter 'row_number()' के लिए धन्यवाद। मैंने प्रश्नों को संपादित किया। –

+0

क्या मैं बाद में एक महीने के भीतर कार्यों का क्रम बदल सकता हूं? – Mario

4

यदि आप प्रति INSERT कथन प्रति डेटा डेटा की एक पंक्ति में तोड़ने के इच्छुक हैं, तो आप PostgreSQL rules का उपयोग कर सकते हैं। उदाहरण है कि निम्न नियमों में उन नियमों में थोड़ा सा गड़बड़ है जो आपको रिश्ते को लिखने के लिए रीडायरेक्ट नहीं करते हैं। यह आमतौर पर ट्रिगर्स के साथ किया जाता है। लेकिन हम अगर यह ट्रिगर्स के बिना संभव है देख रहे हैं, तो यहाँ जाता है:

--drop table table_data cascade; 
CREATE TABLE table_data (
    month integer not null, 
    task integer not null, 
    "desc" text 
); 
ALTER TABLE table_data add primary key (month, task); 

CREATE VIEW "table" as 
select month, task, "desc" from table_data; 

CREATE OR REPLACE RULE calculate_task AS ON INSERT TO "table" 
    DO INSTEAD 
    INSERT into table_data (month, task, "desc") 
    VALUES (
    NEW.month, 
    (select coalesce(max(task),0) + 1 from table_data where month = NEW.month), 
    NEW."desc"); 

BEGIN; 
INSERT INTO "table" ("month", "desc") VALUES (1, 'One thing'); 
INSERT INTO "table" ("month", "desc") VALUES (1, 'Another thing'); 
INSERT INTO "table" ("month", "desc") VALUES (1, 'Last task of the month'); 
INSERT INTO "table" ("month", "desc") VALUES (2, 'Last task of the month'); 
INSERT INTO "table" ("month", "desc") VALUES (2, 'Last task of the month'); 
INSERT INTO "table" ("month", "desc") VALUES (3, 'First of third month'); 
COMMIT; 

select * from "table"; 

नोट्स

  • आप "तालिका" पर DELETE/अद्यतन समर्थन करने की आवश्यकता है, तो आप नियम जोड़ सकता है उन कार्यों के लिए भी।
  • BEGIN और COMMIT उपरोक्त ब्लॉक को यह दिखाने के लिए प्रयोग किया जाता है कि एक ही लेनदेन के भीतर भी, यह विधि तब तक काम करेगी जब तक प्रत्येक पंक्ति अपने INSERT में टूट जाती है।
  • आप table और desc जैसे कुछ reserved words का उपयोग करें। जैसा कि आपने किया है, उन्हें दोबारा उद्धृत करना सुनिश्चित करें और आपको कोई समस्या नहीं होगी।

Here इस तरह यह करने के लिए है sqlfiddle