Select rows using part of UUID4 - postgresql

I have table of users with UUIDv4 as primary key.
How can I select all rows with id starting with 'e2eb5'?
I tried following select:
SELECT * FROM "user" WHERE "id" LIKE 'e2eb5%';
In my application there are less than one thousand users and first part of UUID should be just all info you need to identify them.
Therefore I want user detail to be on url like this:
/users/e2eb5
Instead of:
/users/3b0fbfd6-0661-4880-b5c5-4659ed85fa96
Edit:
Querying it as suggested here: How to query UUID for postgres
where some_uuid between 'e99aec55-0000-0000-0000-000000000000'
and 'e99aec55-ffff-ffff-ffff-ffffffffffff'
is not viable solution as it requires either fixed length of uuid prefix or writing more complex query.

You can convert the id to text and compare how you have in your question.
SELECT *
FROM "user"
WHERE "id"::text LIKE 'e2eb5%';
This needs to convert each row's id to text, so it can be slow with tons or rows. But working with less than 1,000 should be fine.

Related

Postgresql Select based on primary key return null

So I found a bizarre error in my apps, and I still don't know why and what causes this.
So I have attached 3 pictures. The first picture is the query result in beaver, using seeds_tag to search for a user. I found the bugged user and found its ID 27820.
In the second picture, I query using ID 27820, but it returns nothing. The third picture I query using BETWEEN ID 27817 to 27822 shows another number except 27820. Can anyone explain what happened with the id column? it broke my app because my ORM or Postgres query couldn't find that ID while my app used ID as a user identifier.
ID column is primary key, autoincrement bigint.

Is it mandatory to use "" around the table name performing query on PostgreSQL?

I am not so into PostgreSQL and pgAdmin 4 and I have the following doubt.
Following a screenshot of what I can see in my pgAdmin4:
As you can see it is performing this very simple query:
SELECT * FROM public."Example"
ORDER BY id ASC
The thing that I am not understanding is what is this public name in front of the Example table name. What is it?
I was trying to perform a query in this way but it is not working:
SELECT * FROM Example
ORDER BY id ASC
It give me a syntax error. I often used MySql and in MySql it is working.
I tried to replace the query in this way:
SELECT * FROM "Example"
ORDER BY id ASC
and so it is working. So it means that in PosgreSQL database the "" around the table name are mandatory?
The thing that I am not understanding is what is this public name in front of the Example table name. What is it?
As said in postgres documentation:
"By default tables (and other objects) are automatically put into a schema named "public". Every new database contains such a schema."
So it means that in PosgreSQL database the "" around the table name
are mandatory?
Not really but you need to use it if you are using reserved keywords (such as "user","name"and other)or if your table's name contains uppercase(it's your case) letters. Anyways, in this case if you can it's better change your table's name.
You should change your table name to all alphabet in lowercase then try again with
select * from example

Best performance method for getting records by large collection of IDs

I am writing a query with code to select all records from a table where a column value is contained in a CSV. I found a suggestion that the best way to do this was using ARRAY functionality in PostgresQL.
I have a table price_mapping and it has a primary key of id and a column customer_id of type bigint.
I want to return all records that have a customer ID in the array I will generate from csv.
I tried this:
select * from price_mapping
where ARRAY[customer_id] <# ARRAY[5,7,10]::bigint[]
(the 5,7,10 part would actually be a csv inserted by my app)
But I am not sure that is right. In application the array could contain 10's of thousands of IDs so want to make sure I am doing right with best performance method.
Is this the right way in PostgreSQL to retrieve large collection of records by pre-defined column value?
Thanks
Generally this is done with the SQL standard in operator.
select *
from price_mapping
where customer_id in (5,7,10)
I don't see any reason using ARRAY would be faster. It might be slower given it has to build arrays, though it might have been optimized.
In the past this was more optimal:
select *
from price_mapping
where customer_id = ANY(VALUES (5), (7), (10)
But new-ish versions of Postgres should optimize this for you.
Passing in tens of thousands of IDs might run up against a query size limit either in Postgres or your database driver, so you may wish to batch this a few thousand at a time.
As for the best performance, the answer is to not search for tens of thousands of IDs. Find something which relates them together, index that column, and search by that.
If your data is big enough, try this:
Read your CSV using a FDW (foreign data wrapper)
If you need this connection often, you might build a materialized view from it, holding only needed columns. Refresh this when new CSV is created.
Join your table against this foreign table or materialized viev.

If a Postgres DB has unique IDs across its tables, how do you find a row using its ID without knowing its table?

Following the blog of Rob Conery I have set of unique IDs across the tables of my Postgres DB.
Now, using these unique IDs, is there a way to query a row on the DB without knowing what table it is in? Or can those tables be indexed such that if the row is not available on the current table, I just increase the index and I can query to the next table?
In short - if you did not prepared for that - then no. You can prepare for that by generating your own uuid. Please look here. For instance PG has uuid that preserve order. Also uuid v5 has something like namespaces. So you can build hierarchy. However that is done by hashing namespace, and I don't know tool to do opposite inside PG.
If you know all possible tables in advance you could prepare a query that simply UNIONs a search with a tagged type over all tables. In case of two tables named comments and news you could do something like:
PREPARE type_of_id(uuid) AS
SELECT id, 'comments' AS type
FROM comments
WHERE id = $1
UNION
SELECT id, 'news' AS type
FROM news
WHERE id = $1;
EXECUTE type_of_id('8ecf6bb1-02d1-4c04-8875-f1da62b7f720');
Automatically generating this could probably be done by querying pg_catalog.pg_tables and generating the relevant query on the fly.

auto-increment column in PostgreSQL on the fly?

I was wondering if it is possible to add an auto-increment integer field on the fly, i.e. without defining it in a CREATE TABLE statement?
For example, I have a statement:
SELECT 1 AS id, t.type FROM t;
and I am can I change this to
SELECT some_nextval_magic AS id, t.type FROM t;
I need to create the auto-increment field on the fly in the some_nextval_magic part because the result relation is a temporary one during the construction of a bigger SQL statement. And the value of id field is not really important as long as it is unique.
I search around here, and the answers to related questions (e.g. PostgreSQL Autoincrement) mostly involving specifying SERIAL or using nextval in CREATE TABLE. But I don't necessarily want to use CREATE TABLE or VIEW (unless I have to). There are also some discussions of generate_series(), but I am not sure whether it applies here.
-- Update --
My motivation is illustrated in this GIS.SE answer regarding the PostGIS extension. The original query was:
CREATE VIEW buffer40units AS
SELECT
g.path[1] as gid,
g.geom::geometry(Polygon, 31492) as geom
FROM
(SELECT
(ST_Dump(ST_UNION(ST_Buffer(geom, 40)))).*
FROM point
) as g;
where g.path[1] as gid is an id field "required for visualization in QGIS". I believe the only requirement is that it is integer and unique across the table. I encountered some errors when running the above query when the g.path[] array is empty.
While trying to fix the array in the above query, this thought came to me:
Since the gid value does not matter anyways, is there an auto-increment function that can be used here instead?
If you wish to have an id field that assigns a unique integer to each row in the output, then use the row_number() window function:
select
row_number() over () as id,
t.type from t;
The generated id will only be unique within each execution of the query. Multiple executions will not generate new unique values for id.