Dynamisches (spaltenbasiertes) Intervall

70

Wie füge ich JETZT eine dynamische (spaltenbasierte) Anzahl von Tagen hinzu?

SELECT NOW() + INTERVAL a.number_of_days "DAYS" AS "The Future Date" 
FROM a;

Wo a.number_of_daysist eine ganze Zahl?

explodiert
quelle

Antworten:

182

Normalerweise multipliziere ich die Zahl mit interval '1 day'oder ähnlichem, zB:

select now() + interval '1 day' * a.number_of_days from a;
araqnid
quelle
6
7 Jahre später ist dies immer noch die beste Lösung. Tolle.
Greg_Data
Netter Trick, aber es scheint mir, dass die besseren Lösungen die folgenden sind, bei denen sie die verketteten Felder in ein Intervall umwandeln, entweder mit CAST oder :: Intervall.
DeniseMeander
Paul S hat eine flexiblere Lösung.
Jonathan
28

Ich weiß, dass dies ein Jahr alt ist, aber wenn Sie eine Spalte verwenden müssen, um das tatsächliche Intervall anzugeben (z. B. 'Tage', 'Monate'), sollten Sie wissen, dass Sie Ihre Zeichenfolge auch in ein Intervall umwandeln können, indem Sie Folgendes angeben:

SELECT now()+ CAST(the_duration||' '||the_interval AS Interval)

Die ursprüngliche Frage würde also lauten:

SELECT now() + CAST(a.number_of_days||" DAYS" AS Interval) as "The Future Date" FROM a;
Paul S.
quelle
1
Wenn Sie mehr Kontrolle über die Werte in der Einheitenspalte haben möchten, können Sie diese selbst dekodieren:select *, num * case unit when 'W' then '1 week'::interval when 'D' then '1 day'::interval when 'H' then '1 hour'::interval end from (values(1,'W'),(2,'D'),(3,'H')) x(num, unit)
araqnid
danke, das hat mir sehr geholfen. Aber vergessen Sie nicht, die Anführungszeichen für Postgres zu ändern:SELECT now() + CAST(a.number_of_days||' DAYS' AS Interval) as "The Future Date" FROM a;
Leole
18

Ich bevorzuge diesen Weg. Ich finde es ziemlich einfach und sauber. In postgre müssen Sie intervalverwenden +Betreiber mittimestamp

select (3||' seconds')::interval;

select now()+ (10||' seconds')::interval,now();

Hier können Sie Sekunden, Minuten ... Tage, Monate ... verwenden und die Zahlen in Ihrer Spalte ersetzen.

select now()+ (column_name||' seconds')::interval,now()
from your_table;
SüniÚr
quelle
3

Um Intervalle zu erstellen, die auf Spaltenwerten basieren, empfehle ich, Ihrer Tabelle zwei Spalten hinzuzufügen. Beispiel: Spalte "period_value" :: INT4 und Spalte "period_name" :: VARCHAR. In der Spalte "period_name" können folgende Werte gespeichert werden:

  • Mikrosekunde
  • Millisekunden
  • zweite
  • Minute
  • Stunde
  • Tag
  • Woche
  • Monat
  • Quartal
  • Jahr
  • Dekade
  • Jahrhundert
  • Millennium
+ -------------- + ------------- +
| period_value | period_name |
+ -------------- + ------------- +
| 2 | Minute |
+ -------------- + ------------- +

Jetzt können Sie schreiben:

SELECT NOW() - (period_value::TEXT || ' ' || period_name::TEXT)::INTERVAL FROM table;
Igor Manturov Jr.
quelle
Sie implementieren im Wesentlichen die Funktionalität, die der Datentyp intervalbereits bietet. Das Erstellen einer einzelnen Typspalte intervalwäre eine viel bessere Lösung als dieser Hack.
a_horse_with_no_name
2

Verwenden make_interval()

SELECT NOW() + make_interval(days => a.number_of_days) AS "The Future Date" 
FROM a;

Im Allgemeinen ist es jedoch möglicherweise besser, eine Spalte zu verwenden, die als definiert intervalist. Dann können Sie eine beliebige Einheit verwenden, wenn Sie dort einen Wert speichern.

ein Pferd ohne Name
quelle
days => a.number_of_daysPostgres' Schlüsselwort - Syntax zu sein scheint, und hat nur make_interval Parameter für years, months, weeks, days, hours, minsund secs. Das heißt, es würde nicht für alle Einheiten interval '1 millisecond' * msTimefunktionieren, aber es ist in den meisten Fällen immer noch eine faire Alternative.
VLRoyrenn
@VLRoyrenn: secsakzeptiert ein double valueso, wenn Sie Millisekunden verwenden möchtensecs => 0.001
a_horse_with_no_name
0

Wenn wir ein Feld mit einem Intervallzeichenfolgenwert wie "41 Jahre 11 Monate 4 Tage" haben und es in das Geburtsdatum konvertieren möchten, verwenden Sie diese Abfrage:

UPDATE "february14" set dob = date '2014/02/01'  - (patient_age::INTERVAL) 

dob ist Datumsfeld zu konvertieren '41 Jahre 11 mons 4 Tage zu ‚1972.10.14‘ zum Beispiel
patient_age ist varchar Feld , das Zeichenfolge wie '41 Jahre 11 mons 4 Tage haben

Und dies ist eine Abfrage, um das Alter wieder in das Geburtsdatum umzuwandeln

SELECT now() - INTERVAL '41 years 10 mons 10 days';
Mohammad Yusuf
quelle
0

Das Aktualisieren basierend auf einer Spalten-ID war für mich eine nützliche Möglichkeit, zufällige Testdaten zu erstellen.

update study_histories set last_seen_at = now() - interval '3 minutes' * id;
ardochhigh
quelle