SQLite Group concat

W Sqlite mogę użyć group_concat do zrobienia:

1...A
1...B
1...C
2...A
2...B
2...C

1...C,B,A
2...C,B,A

Ale kolejność konkatenacji jest przypadkowa-według docs.

Muszę sortować wyjście group_concat aby było

1...A,B,C
2...A,B,C
Jak mogę to zrobić?
Author: user230781, 2009-12-13

2 answers

Czy nie można użyć elementu podrzędnego z klauzulą order by, a następnie pogrupować wartości concat?

Coś jak

SELECT ID, GROUP_CONCAT(Val)
FROM (
   SELECT ID, Val
   FROM YourTable
   ORDER BY ID, Val
   )
GROUP BY ID;
 68
Author: Adriaan Stander,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-09-24 08:56:09

Aby być bardziej precyzyjnym, zgodnie z docs :

Kolejność konkatenowanych elementów jest dowolna.

To tak naprawdę nie znaczy losowe, to po prostu oznacza, że deweloperzy zastrzegają sobie prawo do korzystania z dowolnego zamówienia, które piszczą, nawet różne dla różnych zapytań lub w różnych wersjach SQLite.

W obecnej wersji, kolejność ta może być tą sugerowaną przez odpowiedź Adriana Standera, ponieważ jego kod wydaje się działać. Więc możesz po prostu strzeż się testów jednostkowych i skończ z tym. Ale bez zbadania kodu źródłowego SQLite naprawdę dokładnie nigdy nie można być 100% pewien, że to zawsze będzie działać.

Jeśli chcesz zbudować SQLite ze źródła, Możesz również spróbować napisać własną zdefiniowaną przez użytkownika funkcję agregacyjną , ale jest łatwiejszy sposób.

Na szczęście, od wersji 3.25.0, masz funkcje okien , zapewniające gwarancję pracy, choć nieco brzydkie rozwiązanie dla Twojego problem.

Jak widać w dokumentacji, funkcje systemu windows mają swoje własne klauzule ORDER BY:

W powyższym przykładzie ramka okna składa się ze wszystkich wierszy pomiędzy poprzednim wierszem ("1 poprzedzający") i następnym wierszem ("1 następny"), włącznie, gdzie wiersze są sortowane zgodnie z klauzulą ORDER BY w window-defn (w tym przypadku "ORDER BY a").

Zauważ, że samo to nie musi oznaczać, że wszystkie funkcje zbiorcze respektują porządek wewnątrz ramki okna, ale jeśli spojrzysz na testy jednostkowe , zobaczysz, że tak naprawdę jest:

do_execsql_test 4.10.1 {
  SELECT a, 
    count() OVER (ORDER BY a DESC),
    group_concat(a, '.') OVER (ORDER BY a DESC) 
  FROM t2 ORDER BY a DESC
} {
  6 1 6
  5 2 6.5
  4 3 6.5.4
  3 4 6.5.4.3
  2 5 6.5.4.3.2
  1 6 6.5.4.3.2.1
  0 7 6.5.4.3.2.1.0
}

Więc podsumowując, możesz napisać

SELECT ID, GROUP_CONCAT(Val) OVER (PARTITION BY ID ORDER BY Val) FROM YourTable;

W wyniku:

1|A
1|A,B
1|A,B,C
2|A
2|A,B
2|A,B,C

Który niestety zawiera również każdy prefiks pożądanych agregacji. Zamiast tego chcesz określić ramki okien, aby zawsze zawierały pełny zakres, a następnie odrzucić nadmiarowe wartości, jak to:

SELECT DISTINCT ID, GROUP_CONCAT(Val)
OVER (PARTITION BY ID ORDER BY Val ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)
FROM YourTable;

Lub w ten sposób:

SELECT * FROM (
    SELECT ID, GROUP_CONCAT(Val)
    OVER (PARTITION BY ID ORDER BY Val ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)
    FROM YourTable
)
GROUP BY ID;
 5
Author: szmate1618,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-07-17 13:09:29