PostgreSQL 抱怨主键中的元素不存在比较函数

PostgreSQL complains about inexistent comparison function for element in primary key

我在 PostgreSQL 数据库中有一个 table,我想在其中存储以下列:

STATION   LOCATION    SERVICE    NORTH    EAST
text      point       text       real     real

每个元组(STATION, LOCATION, SERVICE)都是唯一的,所以我决定把它做成复合类型,并把它作为主键。

但是,当我尝试在数据库中插入新条目时 我收到以下错误psycopg2.ProgrammingError: could not identify a comparison function for type point

我猜它是在抱怨你不能在二维平面中对两个点进行排序,但我看不出这有什么关系。我设法在测试示例中使用了将点用作主键的复合类型,所以我看不出这有什么不同。

我想知道:


调试信息:

testdb=> \d ERROR_KEY
Composite type "public.error_key"
  Column  | Type  | Modifiers 
----------+-------+-----------
 station  | text  | 
 location | point | 
 service  | text  | 

testdb=> \d testtable
    Table "public.testtable"
 Column |   Type    | Modifiers 
--------+-----------+-----------
 key    | error_key | not null
 north  | real      | 
 east   | real      | 
Indexes:
    "testtable_pkey" PRIMARY KEY, btree (key)

作为参考,这是我用于插入的代码:

from collections import namedtuple
import psycopg2

DB_NAME = 'testdb'
DB_USER = 'testuser'
DB_HOST = 'localhost'
DB_PASSWORD = '123456'

PVT_TABLE_NAME = 'testtable'

Coordinate = namedtuple('Coordinate', ['lat', 'lon'])

PVT_Error_Key = namedtuple('PVT_Error_Key',
                           ['station', 'location', 'service'])

PVT_Error_Entry = namedtuple(
    'PVT_Error_Entry', ['key', 'north', 'east'])


def _adapt_coordinate(coord):
    """
    Adapter from Python class to Postgre geometric point
    """
    lat = psycopg2.extensions.adapt(coord.lat)
    lon = psycopg2.extensions.adapt(coord.lon)
    return psycopg2.extensions.AsIs("'(%s, %s)'" % (lat, lon))


def _connect_to_db(db_name, db_user, db_host, db_password):
    """
    Connects to a database and returns a cursor object to handle the connection
    """
    connection_str = ('dbname=\'%s\' user=\'%s\' host=\'%s\' password=\'%s\''
                      % (db_name, db_user, db_host, db_password))
    return psycopg2.connect(connection_str).cursor()


def main():
    # Register the adapter for the location
    psycopg2.extensions.register_adapter(Coordinate, _adapt_coordinate)

    cursor = _connect_to_db(DB_NAME, DB_USER, DB_HOST, DB_PASSWORD)

    # Create a dummy entry
    entry = PVT_Error_Entry(
        key=PVT_Error_Key(station='GKIR',
                          location=Coordinate(lat=12, lon=10),
                          service='E1'),
        north=1, east=2)

    # Insert the dummy entry in the database
    cursor.execute(
        'INSERT INTO %s '
        '(KEY, NORTH, EAST) '
        'VALUES((%%s, %%s, %%s), %%s, %%s)'
        % PVT_TABLE_NAME,
        (entry.key.station, entry.key.location, entry.key.service,
         entry.north, entry.east))

    # Retrieve and print all entries of the database
    cursor.execute('SELECT * FROM %s', (PVT_TABLE_NAME))
    rows = cursor.fetchall()
    print(rows)


if __name__ == '__main__':
    main()

您不能在主键中使用 point 类型的列,例如:

create table my_table(location point primary key);

ERROR:  data type point has no default operator class for access method "btree"
HINT:  You must specify an operator class for the index or define a default operator class for the data type.

报错信息很清楚,需要为类型创建一个完整的btree operatorclass。

此答案中描述了完整的过程:


更新。使用您在评论中提到的解决方法

create table my_table(
    x numeric,
    y numeric,
    primary key (x, y));

insert into my_table values
(1.1, 1.2);

您可以随时创建一个视图,它可以像 table 一样被查询:

create view my_view as
select point(x, y) as location
from my_table;

select *
from my_view;

 location  
-----------
 (1.1,1.2)
(1 row)