Jed Rembold
March 12, 2025
SHOW timezone;SELECT * FROM pg_timezone_abbrevs;SELECT * FROM pg_timezone_names;Change your postgressql.conf file,
which controls your Postgres server. Only recommended if you have
permanently moved elsewhere and the database time zone has not updated
appropriately.
Set future queries in a single session to be from a new timezone:
SET |||timezone||| TO |||time_zone_name_or_abbrv|||;
localtime or
localtimestamp report!Transform a single query to be reported in a different time zone:
SELECT |||dt_col_name||| AT TIME ZONE |||tz_name_or_abbrv|||
FROM |||tablename|||;SELECT or ORDER BY
statements
OVER () keyword, which comes after the
aggregating window function() determines the
“window” of the window functionSELECT AVG(|||col|||) OVER ()
FROM |||table name|||;| Function | Description |
|---|---|
row_number() |
Assigns an ascending row number to each row in a window |
rank() |
Assigns an ascending rank to each row, with possible ties skipping the next value |
dense_rank() |
Assigns an ascending rank to each row, with possible ties not skipping the next value |
first_value(|||col|||) |
Returns the first value in the window of column
|||col||| |
last_value(|||col|||) |
Returns the last value in the window of column
|||col||| |
lag(|||col|||) |
Returns the previous row of column
|||col||| |
lead(|||col|||) |
Returns the next row of column
|||col||| |
nth_value(|||col|||, |||n|||) |
Returns the |||n|||th row of column
|||col||| (NULL if
doesn’t exist) |
OVER () statementSELECT COUNT(*) OVER (ORDER BY |||col|||)
FROM |||table name|||;
You can tweak this window by specifying the starting and stopping point, using the syntax:
...|||type||| BETWEEN |||offset||| PRECEDING AND |||offset||| FOLLOWING
which appears in the OVER clause, after
any provided ordering
|||type||| can be either
ROWS, RANGE, or
GROUP|||offset||| can be
UNBOUNDED if the type is
ROWS or GROUPRANGECan also exclude the current row or group from the window:
... EXCLUDE |||type||||||type||| here can be:
CURRENT ROW, which excludes the current
row from the windowGROUP which excludes the current row and
all other rows currently tied with itTIES which just excludes the tied rows,
but keeps the current rowGROUP BY, but
every row will get a value hereSELECT AVG(|||column|||) OVER (
PARTITION BY |||column|||
)
FROM |||table|||;
GROUP BY and
HAVING can be very useful here!
GROUP BY all the columns that you want to
check for repetitionHAVING to only grab those groups that
have more than one element (and thus a repetition)SELECT |||col1, col2, col3, col4|||, COUNT(*)
FROM |||table name|||
GROUP BY |||col1, col2, col3, col4|||
HAVING COUNT(*) > 1;SELECT
COUNT(*) - COUNT(|||col1|||) as col1,
COUNT(*) - COUNT(|||col2|||) as col2
FROM |||table name|||;
GROUP BY effectively, you really
need categories to be consistently named across the data setGROUP BY could do similar but add
counts
ALTER TABLEUPDATE
ALTER TABLE is generally followed by
the table name and then another keyword command, depending on what you
want to do
ALTER TABLE |||table name||| ...
Adding columns:
... ADD COLUMN |||column name||| ||| desired data type|||;Removing columns
... DROP COLUMN |||column name|||;ALTER TABLE |||table name||| ...
Changing columns
... ALTER COLUMN |||column name||| SET DATA TYPE |||data type|||;
... ALTER COLUMN |||column name||| SET NOT NULL;Renaming columns
... RENAME |||column name||| TO |||new column name|||;Rename entire table
... RENAME TO |||new table name|||;UPDATE itUPDATE sets particular columns to a
particular value
UPDATE |||table name|||
SET |||column name||| = |||new value|||;WHEREFrequently, if you are about to heavily modify a table, you should consider working on a backup copy
We actually have already seen the basic machinery for this:
CREATE TABLE |||new table||| AS
SELECT * FROM |||original table|||;Note: Indexes and constraints are stored separately, and so are NOT copied over using this process!
For including constraints and indexes, you can use a Postgres specific syntax, but the newly created table will initially be missing the data
CREATE TABLE |||new table|||
(LIKE |||original table||| INCLUDING ALL);In some cases, you’ll want to update or pass information across tables
In core SQL, you’d need to use subqueries, which we’ll be talking about in a few chapters
In Postgres, to update, you can use
FROM:
UPDATE table_name1
SET |||column name||| = table_name2.|||column name|||
FROM table_name2
WHERE table_name1.|||col1||| = table_name2.|||col1|||;To insert values from another table into another:
INSERT INTO |||new table||| SELECT * FROM |||original table|||;DROP for removing aspects of a table like
columns, constraints, indexes, or the table itselfDELETE FROM for removing rows from
tablesDROP will frequently come after an
ALTER TABLE unless you are dropping the table
itselfDELETE FROM without a filter will
delete all rows
ALTER TABLE |||table name||| DROP COLUMN |||column name|||;
ALTER TABLE |||table name||| DROP CONSTRAINT |||constraint name|||;
DROP INDEX |||index name|||;
DROP TABLE |||table name|||;
DELETE FROM |||table name|||; -- All rows gone!
DELETE FROM |||table name||| WHERE |||condition true|||;
START TRANSACTION; or
BEGIN;COMMIT; actually makes the changesROLLBACK; throws out everything within
the transactionclean.sql file to add whatever
commands you need to move, organize, and clean your data.clean.sql file back to your
repository, keeping the filename the same!You’ll need to create more tables to organize your data. These
get run a single time, so they should not go in
clean.sql!
It can be useful to empty out your original dumping table after you organize things each time so that you don’t “double process” anything
If you are getting duplicate information occasionally through your API, it can be useful to understand “Upserting”:
INSERT INTO |||new table||| VALUES
SELECT |||special id, other cols||| FROM |||old table|||
ON CONFLICT |||column or constraint name|||
DO NOTHING