2017-08-02 9 views
9

Mam column w SQL table. Zawiera on date zamówienia dostawy.Jak obliczyć obrót w każdym semestrze

Tak samo datę można powtarzać (w ciągu jednego dnia możemy delivred severals zamówienie), na przykład:

05-01-16 
05-01-16 
05-01-16 
08-01-16 
08-01-16 
14-01-16 
22-01-16 
22-01-16 
04-02-16 
05-02-16 
05-02-16 

Chcę, obliczyć AVG obrotów każdego artykułu w each 6 months, wyjaśniam więcej:

From January to June ==> Turnover 1 
From Febrary to July ==> Turnover 2 
From March to August ==> Turnover 3 
From April to September ==> Turnover 4 
From May to Obtober ==> Turnover 5 
From June to November ==> Turnover 6 
From July to December ==> Turnover 7 

ja już wyodrębnione miesiąc przez żądanie mieszka, ale nie mogę obliczyć dynamicznie (bo moje dane powinny być zmiany w każdym miesiącu) obroty jak ten powyższy przykład:

select distinct extract (month from Article) as mt 
order by mt 

Próbowałem użyć cursor, ale nie mogę znaleźć najlepszego rozwiązania.

Zrobiłem wniosek obliczyć obrót dla każdego klienta za artykuł w the first 6 months (zrobiłem to ręcznie) jest następujący:

select "LRU", "Client", round(sum("Montant_fac_eur")) 
from "foundry" 
where "Nature"='Repair' 
and "Client"={{w_widget3.selectedValue}} 
and "annee"='2016' 
and extract (month from "date") between '1' and '6' 


group by "LRU", "Client" 

Jej wynik jest następujący:

LRU   Client round 
"article1"  4001 8859  Turnover of article1 from January to June 
"article2"  4001 94315 Turnover of article2 from January to June 
"article3"  4001 273487 Turnover of article3 from January to June 
"article4"  4001 22292 Turnover of article4 from January to June 
"article5"  4001 22292 Turnover of article5 from January to June 
"article6"  4001 42590 Turnover of article6 from January to June 
"article7"  4001 9965  Turnover of article7 from January to June 
"article8"  4001 39654 Turnover of article8 from January to June 
"article9"  4001 3883  Turnover of article9 from January to June 
"article10"  4001 41612 Turnover of article10 from January to June 

I chcesz zrobić pętlę, aby obliczyć obrót co 6 miesięcy bez ręcznego zapisywania, jeśli to możliwe? Czy ktoś może mi pomóc i dać mi rozwiązanie lub sugestię, jak mogę to zrobić? Dziękuję.

+2

mógłbyś pisać wejście próbki i oczekiwanego wyjście? –

+0

Zmieniłem moje pytanie powyżej. Dziękuję Ci. – vero

+0

bardzo przydatne byłoby uzyskanie schematu tabeli "odlewniczej" bez danych wrażliwych. Na przykład. zmień nazwy kolumn. –

Odpowiedz

6

Tutaj można zobaczyć uproszczoną definicję i rozwiązanie problemu (jeśli dobrze zrozumiałem): http://sqlfiddle.com/#!9/48a2e1/1

CREATE TABLE foundry 
(
    lru varchar(50) NOT NULL, 
    client int NOT NULL, 
    purchase_date date, 
    price int NOT NULL 
); 

INSERT INTO foundry (lru, client, purchase_date, price) VALUES 
("article1", 4001, "01-01-16", 100), 
("article1", 4001, "01-01-17", 200), 
("article1", 4001, "01-02-16", 300), 
("article1", 4001, "01-04-16", 400), 
("article1", 4001, "01-06-16", 500), 
("article1", 4001, "01-08-16", 600), 
("article1", 4001, "01-10-16", 700), 
("article1", 4001, "01-11-16", 800), 
("article1", 4002, "01-01-16", 900), 
("article1", 4002, "01-07-16", 1000), 
("article1", 4002, "01-12-16", 1100); 

Zasadniczo mamy stół z czterema kolumnami: LRU (nazwa artykułu), klient, data zakupu i cena.

Rozwiązanie wygląda następująco:

SELECT lru, client, avg(price), COUNT(*) as total_items, 
MONTHNAME(STR_TO_DATE(L, '%m')) as start_month, MONTHNAME(STR_TO_DATE(R, '%m')) as end_month FROM foundry, 
(
    SELECT 1 as L, 6 as R 
    UNION ALL 
    SELECT 2, 7 
    UNION ALL 
    SELECT 3, 8 
    UNION ALL 
    SELECT 4, 9 
    UNION ALL 
    SELECT 5, 10 
    UNION ALL 
    SELECT 6, 11 
    UNION ALL 
    SELECT 7, 12 
) months 
WHERE month(purchase_date) >= L AND month(purchase_date) <= R 
GROUP BY lru, client, L, R 

Chodzi o to:

  1. wygenerować wszystkie możliwe kombinacje miesięcy, 1-6, 2-7, ..., 7,12
  2. Dołącz do danych źródłowych z generowane miesięczną połączeniu
  3. Zastosowanie AVG z GROUP BY

A wynik:

lru  client avg(price) total_items  start_month  end_month 
article1 4001 300  5 January  June 
article1 4001 400  3 February July 
article1 4001 500  3 March August 
article1 4001 500  3 April September 
article1 4001 600  3 May  October 
article1 4001 650  4 June November 
article1 4001 700  3 July December 
article1 4002 900  1 January  June 
article1 4002 1000 1 February July 
article1 4002 1000 1 March August 
article1 4002 1000 1 April September 
article1 4002 1000 1 May  October 
article1 4002 1000 1 June November 
article1 4002 1050 2 July December 
+0

Co około 6-miesięcznych interwałów, które rozpoczynają się w drugiej połowie roku, np. 8-1 (w przyszłym roku)? – miazo

+0

Następnie powinniśmy ulepszyć zapytanie za pomocą UNION ALL. Powinniśmy również wziąć pod uwagę rok. Moglibyśmy więc generować możliwe kombinacje miesiąca i lat. {generated_month_combinations} dołącz {possible_years} –

+0

Dobra odpowiedź tvelkyy dzięki za poświęcenie czasu na wyjaśnienie. – Rob212

2

Polecam wspólne wyrażenia tabel dla każdego sześciomiesięcznego zasięgu. https://technet.microsoft.com/en-us/library/ms186243(v=sql.105).aspx odczuwalna: z TP1 (Turnoverperiod, Averagevaule) jak ( wybrać 'Period1' jako Turnoverperiod, AVG (obroty) jako Averagevalue gdzie data pomiędzy period1.startdate i period2.enddate ) , TP2 jak ( .... TP2 )

select * from tp1 unii select * from TP2

można również utworzyć dynamiczny ciąg sql (nvarchar (max)), można programowo dołączać kwerendy związków, a następnie użyć instrukcji sp_executesql.

+0

"Okres", "Okres1" i "Okres2" to kolumny? ponieważ moja kolumna, która zawiera datę jej struktury, jak w powyższym przykładzie, więc w tym przypadku powinienem napisać te okres ręcznie. – vero

2

nie jestem pewien, który RDBMS używasz, więc o możliwe rozwiązanie z ANSI SQL (używać analog RDBMS)

adres Spróbuj tego problemu w 2 etapach:

  1. utworzyć widok w formie (powiedzmy to nazwać v_turnover_per_month), stosując podstawową grupę o składni nad stołem źródło:

    article month turnover 
    art1  201701 1000 
    art1  201702 1020 
    ...  ...  ... 
    art2  201701 5000 
    ...  ...  ... 
    
  2. używać następujących instrukcji wyboru

    SELECT article, 
         'Turnover from ' || m1.month || ' until ' || m6.month as title, 
         max(m1.turnover + m2.turnover + m3.turnover + m4.turnover + m5.turnover + m6.turnover) as total_turnover_6month 
    
    FROM v_turnover_per_month as m6 
    JOIN v_turnover_per_month as m5 ON m6.article = m5.article and m5.month+1=m6.month 
    JOIN v_turnover_per_month as m4 ON m6.article = m4.article and m4.month+1=m5.month 
    JOIN v_turnover_per_month as m3 ON m6.article = m3.article and m3.month+1=m4.month 
    JOIN v_turnover_per_month as m2 ON m6.article = m2.article and m2.month+1=m3.month 
    JOIN v_turnover_per_month as m1 ON m6.article = m1.article and m1.month+1=m2.month 
    
    GROUP BY 1, 2; 
    
+0

OP używa mysql –

2

Oto moje zdanie:

DROP TABLE IF EXISTS test; 

# credit to tvelykyy for providing some test data and table def which I adapted 
CREATE TABLE test (lru VARCHAR(16), `client` INTEGER UNSIGNED, purchase_date DATE, price int NOT NULL); 

INSERT INTO test (lru, client, purchase_date, price) VALUES 
("article1", 4001, '2016-01-01', 100), 
("article1", 4001, '2016-02-01', 200), 
("article1", 4001, '2016-03-01', 300), 
("article1", 4001, '2016-04-01', 400), 
("article1", 4001, '2016-05-01', 500), 
("article1", 4001, '2016-06-01', 600), 
("article1", 4001, '2016-07-01', 700), 
("article1", 4001, '2016-08-01', 800), 
("article1", 4002, '2016-01-01', 1100), 
("article1", 4002, '2016-06-01', 1200); 

SELECT A.lru, A.`client`, ROUND(SUM(price)) round, CONCAT('Turnover of article ', A.lru, ' from ', DATE_FORMAT(DATE_ADD(MAX(B.purchase_date), INTERVAL -6 MONTH), '%M %Y'), ' to ', DATE_FORMAT(MAX(B.purchase_date), '%M %Y')) period FROM 
    (
    SELECT DISTINCT lru, LAST_DAY(purchase_date) purchase_month, `client` FROM test 
) A 
LEFT OUTER JOIN 
    test B 
ON A.lru = B.lru AND A.`client` = B.`client` AND A.purchase_month >= LAST_DAY(B.purchase_date) AND DATE_ADD(A.purchase_month, INTERVAL -6 MONTH) < LAST_DAY(B.purchase_date) 
GROUP BY A.lru, A.`client`, A.purchase_month 
ORDER BY A.lru, A.`client`, A.purchase_month; 

Kwerenda działa poprzez wybranie DISTINCT LRU, klientów i miesiące w Podzapytanie A która pozwala LEFT JOIN powrotem do oryginalnych danych ON lru, klienta i datę w ciągu ostatnich sześciu miesięcy, wykorzystując ostatni dzień każdego miesiąca, aby zdefiniować miesiące w standardowy sposób. Ostatecznie agregacja jest używana zgodnie z podaną.

Proszę dać mi znać, jeśli potrzebujesz więcej informacji lub nie rozumiem pytania w całości.

Dzięki

James