यह संदेहास्पद लगता है, लेकिन यह एक प्रश्न का नरक . है ।
मान्यताएं
- आपकी गणनाएं
integer
हैं । - टेबल बुक में सभी कॉलम परिभाषित हैं
NOT NULL
। -
समग्र
(name, sid, date)
तालिका में अद्वितीय हैbook
. आपके पास एकUNIQUE
होना चाहिए बाधा, अधिमानतः (प्रदर्शन के लिए) इस . में कॉलम के साथ आदेश:UNIQUE(sid, date, name)
यह स्वचालित रूप से प्रदर्शन के लिए आवश्यक सूचकांक प्रदान करता है। (अन्यथा एक बनाएं।) देखें:
crosstab()
प्रश्न
शीर्ष प्रदर्शन और छोटी क्वेरी स्ट्रिंग प्राप्त करने के लिए (विशेषकर यदि आप इस क्वेरी को अक्सर चलाते हैं) मैं अतिरिक्त मॉड्यूल का सुझाव देता हूं tablefunc
विभिन्न crosstab()
प्रदान करना कार्य। बुनियादी निर्देश:
मूल क्वेरी
आपको पहले ये अधिकार प्राप्त करने होंगे।
पिछले 10 दिन:
SELECT DISTINCT date
FROM book
WHERE sid = 1
ORDER BY date DESC
LIMIT 10;
विंडो फ़ंक्शन का उपयोग करके पिछले 10 दिनों के नंबर dense_rank()
कोड>
:
SELECT *
FROM (
SELECT name
, dense_rank() OVER (ORDER BY date DESC) AS date_rnk
, count
FROM book
WHERE sid = 1
) sub
WHERE date_rnk < 11
ORDER BY name, date_rnk DESC;
(इस क्वेरी में वास्तविक तिथियां शामिल नहीं हैं।)
आउटपुट कॉलम के लिए कॉलम नाम (पूर्ण समाधान के लिए):
SELECT 'bookname, "' || string_agg(to_char(date, 'DD/MM/YYYY'), '", "' ORDER BY date) || '"'
FROM (
SELECT DISTINCT date
FROM book
WHERE sid = 1
ORDER BY date DESC
LIMIT 10
) sub;
स्थिर कॉलम नामों के साथ सरल परिणाम
यह आपके लिए काफी अच्छा हो सकता है - लेकिन हम परिणाम में वास्तविक तिथियां नहीं देखते हैं:
SELECT * FROM crosstab(
'SELECT *
FROM (
SELECT name
, dense_rank() OVER (ORDER BY date DESC) AS date_rnk
, count
FROM book
WHERE sid = 1
) sub
WHERE date_rnk < 11
ORDER BY name, date_rnk DESC'
, 'SELECT generate_series(10, 1, -1)'
) AS (bookname text
, date1 int, date2 int, date3 int, date4 int, date5 int
, date6 int, date7 int, date8 int, date9 int, date10 int);
बार-बार उपयोग के लिए मेरा सुझाव है कि आप इसे (बहुत तेज़) सामान्य सी फ़ंक्शन को 10 पूर्णांक स्तंभों के लिए एक बार बनाएं, ताकि चीजों को थोड़ा सरल किया जा सके:
CREATE OR REPLACE FUNCTION crosstab_int10(text, text)
RETURNS TABLE (bookname text
, date1 int, date2 int, date3 int, date4 int, date5 int
, date6 int, date7 int, date8 int, date9 int, date10 int)
LANGUAGE C STABLE STRICT AS
'$libdir/tablefunc','crosstab_hash';
इस संबंधित उत्तर में विवरण:
तब आपका कॉल बन जाता है:
SELECT * FROM crosstab(
'SELECT *
FROM (
SELECT name
, dense_rank() OVER (ORDER BY date DESC) AS date_rnk
, count
FROM book
WHERE sid = 1
) sub
WHERE date_rnk < 11
ORDER BY name, date_rnk DESC'
, 'SELECT generate_series(10, 1, -1)'
); -- no column definition list required!
डायनेमिक कॉलम नामों के साथ पूर्ण समाधान
आपका वास्तविक प्रश्न अधिक जटिल है, आप गतिशील कॉलम नाम भी चाहते हैं।
किसी दी गई तालिका के लिए, परिणामी क्वेरी इस तरह दिख सकती है:
SELECT * FROM crosstab_int10(
'SELECT *
FROM (
SELECT name
, dense_rank() OVER (ORDER BY date DESC) AS date_rnk
, count
FROM book
WHERE sid = 1
) sub
WHERE date_rnk < 11
ORDER BY name, date_rnk DESC'
, 'SELECT generate_series(10, 1, -1)'
) AS t(bookname
, "04/11/2015", "05/11/2015", "06/11/2015", "07/11/2015", "08/11/2015"
, "09/11/2015", "10/11/2015", "11/11/2015", "15/11/2015", "17/11/2015");
डायनामिक कॉलम नामों को डिस्टिल करने में कठिनाई होती है। या तो क्वेरी स्ट्रिंग को हाथ से इकट्ठा करें, या (बल्कि बहुत अधिक) इस फ़ंक्शन को यह आपके लिए करने दें:
CREATE OR REPLACE FUNCTION f_generate_date10_sql(_sid int = 1)
RETURNS text
LANGUAGE sql AS
$func$
SELECT format(
$$SELECT * FROM crosstab_int10(
'SELECT *
FROM (
SELECT name
, dense_rank() OVER (ORDER BY date DESC) AS date_rnk
, count
FROM book
WHERE sid = %1$s
) sub
WHERE date_rnk < 11
ORDER BY name, date_rnk DESC'
, 'SELECT generate_series(10, 1, -1)'
) AS ct(bookname, "$$
|| string_agg(to_char(date, 'DD/MM/YYYY'), '", "' ORDER BY date) || '")'
, _sid)
FROM (
SELECT DISTINCT date
FROM book
WHERE sid = 1
ORDER BY date DESC
LIMIT 10
) sub
$func$;
कॉल करें:
SELECT f_generate_date10_sql(1);
यह वांछित क्वेरी उत्पन्न करता है , जिसे आप बदले में निष्पादित करते हैं।
db<>fiddle यहां