Python 使用包含唯一约束的实际值创建SQLITE表的最佳方法是什么?

Python 使用包含唯一约束的实际值创建SQLITE表的最佳方法是什么?,python,sql,database,sqlite,data-structures,Python,Sql,Database,Sqlite,Data Structures,我试图理解处理SQLITE3中浮点比较的最佳方法。一般来说,我理解测试浮动是否相等是一种不好的做法。但是,我不确定在SQLITE关系数据库中如何执行此操作 根据定义,对表中的行使用唯一约束是为了测试相等性。那么,在处理真实数据类型时,这是一种糟糕的做法吗 如果我想选择唯一的行,只知道真正的值,我应该怎么做 我在SQLITE3中有下表: CREATE TABLE nodes( node_id INTEGER PRIMARY KEY, node_number INTEGER,

我试图理解处理SQLITE3中浮点比较的最佳方法。一般来说,我理解测试浮动是否相等是一种不好的做法。但是,我不确定在SQLITE关系数据库中如何执行此操作

根据定义,对表中的行使用唯一约束是为了测试相等性。那么,在处理真实数据类型时,这是一种糟糕的做法吗

如果我想选择唯一的行,只知道真正的值,我应该怎么做

我在SQLITE3中有下表:

CREATE TABLE nodes(
    node_id INTEGER PRIMARY KEY,
    node_number INTEGER,
    x REAL,
    y REAL,
    z REAL,
    UNIQUE(node_number, x, y, z)
);
对于表插入,我执行以下操作:

INSERT OR IGNORE INTO
    nodes(node_number, x, y, z)
VALUES
    (?, ?, ?, ?);
SELECT
    node_id
FROM
    nodes
WHERE
    node_number = ?
AND
    x = ?
AND
    y = ?
AND
    z = ?;
要查找后续插入的节点\u id,请执行以下操作:

INSERT OR IGNORE INTO
    nodes(node_number, x, y, z)
VALUES
    (?, ?, ?, ?);
SELECT
    node_id
FROM
    nodes
WHERE
    node_number = ?
AND
    x = ?
AND
    y = ?
AND
    z = ?;

一种选择可能是将值存储为格式化字符串,并对其强制唯一约束

CREATE TABLE nodes(
    node_id INTEGER PRIMARY KEY,
    node_number INTEGER,
    x TEXT,
    y TEXT,
    z TEXT,
    UNIQUE(node_number, x, y, z)
);
其中,浮点值存储在:

CREATE TABLE node_values(
    node_value_id INTEGER PRIMARY KEY,
    node_id REFERENCES nodes(node_id),
    x REAL,
    y REAL,
    z REAL,
    UNIQUE(node_id)
);
插入内容可能如下所示:

蟒蛇

...
node_values = [
    (nnum1, x1, y1, z1),
    (nnum2, x2, y2, z2),
    ...
]
sql_insert_text_vals = """
INSERT OR IGNORE INTO
    nodes(node_number, x, y, z)
VALUES
    (?, ?, ?, ?);
"""
text_values = [
    (node_number, f'{xval:.10f}', f'{yval:.10f}', f'{zval:.10f}')
    for node_number, xval, yval, zval
    in node_values
]
cursor.executemany(sql_insert_text_vals, text_values)

sql_query = """
SELECT
    node_id
VALUES
    (?, ?, ?, ?);
"""
node_ids = [
    cursor.fetchone()[0]
    for value in text_values
    for cursor.execute(sql_query, value)
]

sql_insert_node_values = """
INSERT OR IGNORE INTO
    node_values(node_id, x, y, z)
VALUES
    (?, ?, ?, ?);
"""
real_values = [
    (node_id, xval, yval, zval)
    for node_id, (node_number, xval, yval, zval)
    in zip(node_ids, node_values)
]
cursor.executemany(sql_insert_node_values, real_values)

这样更好吗?

一个选项可能是将值存储为格式化字符串,并对其强制唯一约束

CREATE TABLE nodes(
    node_id INTEGER PRIMARY KEY,
    node_number INTEGER,
    x TEXT,
    y TEXT,
    z TEXT,
    UNIQUE(node_number, x, y, z)
);
其中,浮点值存储在:

CREATE TABLE node_values(
    node_value_id INTEGER PRIMARY KEY,
    node_id REFERENCES nodes(node_id),
    x REAL,
    y REAL,
    z REAL,
    UNIQUE(node_id)
);
插入内容可能如下所示:

蟒蛇

...
node_values = [
    (nnum1, x1, y1, z1),
    (nnum2, x2, y2, z2),
    ...
]
sql_insert_text_vals = """
INSERT OR IGNORE INTO
    nodes(node_number, x, y, z)
VALUES
    (?, ?, ?, ?);
"""
text_values = [
    (node_number, f'{xval:.10f}', f'{yval:.10f}', f'{zval:.10f}')
    for node_number, xval, yval, zval
    in node_values
]
cursor.executemany(sql_insert_text_vals, text_values)

sql_query = """
SELECT
    node_id
VALUES
    (?, ?, ?, ?);
"""
node_ids = [
    cursor.fetchone()[0]
    for value in text_values
    for cursor.execute(sql_query, value)
]

sql_insert_node_values = """
INSERT OR IGNORE INTO
    node_values(node_id, x, y, z)
VALUES
    (?, ?, ?, ?);
"""
real_values = [
    (node_id, xval, yval, zval)
    for node_id, (node_number, xval, yval, zval)
    in zip(node_ids, node_values)
]
cursor.executemany(sql_insert_node_values, real_values)

这更好吗?

在SQLite中,检查约束不能有子查询,因此如果您想在SQLite本身中执行邻近性检查,则必须使用触发器,例如:

CREATE TRIGGER notequal
   BEFORE INSERT ON test
BEGIN
  SELECT CASE
    WHEN (EXISTS (SELECT r FROM test WHERE abs(NEW.r - r) < 0.1))
    THEN RAISE (ABORT,'Value too close to an existing value')
  END;
END;

当然,您也希望在更新中使用相同的内容。

在SQLite中,检查约束不能有子查询,因此如果您希望在SQLite本身中执行近似检查,则必须使用触发器,例如:

CREATE TRIGGER notequal
   BEFORE INSERT ON test
BEGIN
  SELECT CASE
    WHEN (EXISTS (SELECT r FROM test WHERE abs(NEW.r - r) < 0.1))
    THEN RAISE (ABORT,'Value too close to an existing value')
  END;
END;

当然,对于更新,您也需要相同的内容。

您可以检查类似于absa-b>=0.01的内容。也许您可以定义一个自定义https://docs.sqlalchemy.org/en/13/core/constraints.htmlsqlalchemy.schema.UniqueConstraint 并覆盖uuu eq uuu,但是你必须询问SQLAlchemy的专业人士,你提供的链接中的一个建议是使用十进制类型。然而,当我阅读Sqlite文档时,似乎Sqlite只是将其转化为一个真实的数据库引擎,而其他数据库引擎的工作方式与Python的Decimal类类似。我想知道我是否可以只乘以所需的精度10^9,然后将其存储为整数?对我来说,这一切似乎比它应该的更骇人听闻。您可以检查absa-b>=0.01之类的内容,或者您可以定义一个自定义https://docs.sqlalchemy.org/en/13/core/constraints.htmlsqlalchemy.schema.UniqueConstraint 并覆盖_eq _,但您必须询问SQLAlchemy专业人士。您提供的链接中的一个建议是使用十进制类型。然而,当我阅读Sqlite文档时,似乎Sqlite只是将其转化为一个真实的数据库引擎,而其他数据库引擎的工作方式与Python的Decimal类类似。我想知道我是否可以只乘以所需的精度10^9,然后将其存储为整数?这一切对我来说似乎比应该的更骇人。我不知道触发器。我想你应该把0.1改成期望的精度水平?我不知道触发器。我想您应该将0.1更改为所需的精度级别?