JOIN表与自身,并按位操作过滤每个表中的行

时间:2015-04-23 00:18:13

标签: sql postgresql database-design left-join

我有下表,

-- Generated with pg_dump, some constraints are missing
CREATE TABLE articulos_factura_venta (
    fila integer NOT NULL,
    cantidad integer NOT NULL,
    color integer NOT NULL,
    talla integer NOT NULL,
    estado integer DEFAULT 2 NOT NULL,
    origen integer,
    factura integer NOT NULL,
    articulo integer NOT NULL,
    precio integer NOT NULL,
    vendedor integer,
    anulado boolean DEFAULT false,
    iva double precision DEFAULT 12.0,
    fecha date DEFAULT ('now'::text)::date NOT NULL
);

它包含以下行 1

 fila | cantidad | color | talla | estado | origen | factura | articulo | precio | vendedor | anulado | iva |   fecha    
------+----------+-------+-------+--------+--------+---------+----------+--------+----------+---------+-----+------------
    0 |        1 |     0 |     3 |      6 |     18 |   28239 |     1325 |    455 |        6 | f       |   0 | 2015-04-22
    1 |        1 |     0 |     2 |      6 |     93 |   28239 |     2071 |    615 |        6 | f       |   0 | 2015-04-22
    2 |        1 |     0 |    49 |      6 |     76 |   28239 |     2013 |    545 |        6 | f       |   0 | 2015-04-22
    3 |        1 |     0 |    78 |      6 |     85 |   28239 |     2042 |    235 |        6 | f       |   0 | 2015-04-22
    4 |        1 |     0 |    49 |      6 |     81 |   28239 |     2026 |    615 |        6 | f       |   0 | 2015-04-22
    5 |        1 |     0 |    50 |      6 |     90 |   28239 |     2051 |    755 |        6 | f       |   0 | 2015-04-22
    6 |        1 |     0 |     1 |     38 |     21 |   28239 |     1780 |    495 |        6 | f       |   0 | 2015-04-22
    7 |        1 |    15 |     2 |     38 |     16 |   28239 |     1323 |    845 |        6 | f       |   0 | 2015-04-22
    8 |        1 |     0 |     4 |     38 |     18 |   28239 |     1326 |    455 |        6 | f       |   0 | 2015-04-22
    2 |        1 |     0 |    49 |     22 |     76 |   28239 |     2013 |    545 |        6 | f       |   0 | 2015-04-22

问题非常简单,为什么这个查询不输出任何行?

SELECT
    filas.factura,
    filas.fila,
    filas.cantidad,
    retirados.cantidad,
    vendidos.cantidad,
    filas.estado
FROM
    articulos_factura_venta AS filas
LEFT JOIN
    articulos_factura_venta AS retirados
    USING (fila, color, talla, origen, factura, articulo, vendedor)
LEFT JOIN
    articulos_factura_venta AS vendidos
    USING (fila, color, talla, origen, factura, articulo, vendedor)
JOIN
    articulos
    ON articulos.codigo = filas.articulo
JOIN
    tallas
    ON tallas.codigo = filas.talla
JOIN
    colores
    ON colores.codigo = filas.color
JOIN
    empleados
    ON empleados.codigo = filas.vendedor
WHERE
    filas.factura = 28239 AND 
    retirados.estado & 16 <> 0 AND 
    vendidos.estado & 8 <> 0 AND
    filas.estado & 4 <> 0
ORDER BY
    filas.estado

我希望此查询从cantidad fila == 2的{​​{1}}行中减去estado & 16 <> 0,因此我预计只有一行fila == 2和{{1} }

注意:位标志不是硬编码的,它们是我在用c ++编写的实际应用程序中使用的cantidad = 0

表定义

enum

[1] 该表包含数千行,但我只对这些行感兴趣,即database# \d articulos_factura_venta Column | Type | Modifiers ----------+------------------+-------------------------------------- fila | integer | not null cantidad | integer | not null color | integer | not null talla | integer | not null estado | integer | not null default 2 origen | integer | factura | integer | not null articulo | integer | not null precio | integer | not null vendedor | integer | anulado | boolean | default false iva | double precision | default 12.0 fecha | date | not null default ('now'::text)::date Indexes: "articulos_factura_venta_pkey" PRIMARY KEY, btree (fila, factura, articulo, precio, talla, color, estado) "buscar_cantidad_venta_idx" btree (articulo, talla, color, origen) Foreign-key constraints: "cantidades_venta_articulo_fkey" FOREIGN KEY (articulo) REFERENCES articulos(codigo) "cantidades_venta_color_fkey" FOREIGN KEY (color) REFERENCES colores(codigo) ON UPDATE CASCADE ON DELETE RESTRICT "cantidades_venta_factura_fkey" FOREIGN KEY (factura) REFERENCES ventas(codigo) "cantidades_venta_origen_fkey" FOREIGN KEY (origen) REFERENCES compras(codigo) ON UPDATE CASCADE ON DELETE RESTRICT "cantidades_venta_talla_fkey" FOREIGN KEY (talla) REFERENCES tallas(codigo) ON UPDATE CASCADE ON DELETE RESTRICT "cantidades_venta_vendedor_fkey" FOREIGN KEY (vendedor) REFERENCES empleados(codigo) 的行。

2 个答案:

答案 0 :(得分:2)

长话短说,它可能会像这样:

WHERE

特别是这些添加的LEFT JOIN条款使您尝试JOIN的相应表格无效,并使其表现得像AND r.estado & 16 <> 0 AND v.estado & 8 <> 0

JOIN   empleados e ON e.codigo = f.vendedor

另一个棘手的细节:

f.vendedor

NULL可以是f.vendedor IS NULL。您打算从结果中删除articulos的所有行吗?因为这就是联接的作用。

我评论了tallascoloresNOT NULL的三个联接。 FK列为serial,连接只会花费成本时间而您不使用任何列。

表定义

超过7列的主键约束是糟糕的主意。昂贵而笨重。添加代理主键 - 我建议使用UNIQUE列:

您仍然可以使用CREATE TABLE articulos_factura_venta ( afv_id serial PRIMARY KEY -- pick your column name fila integer NOT NULL, cantidad integer NOT NULL, color integer NOT NULL, talla integer NOT NULL, estado integer DEFAULT 2 NOT NULL, factura integer NOT NULL, articulo integer NOT NULL, precio integer NOT NULL, fecha date NOT NULL DEFAULT now()::date, origen integer, vendedor integer, anulado boolean DEFAULT false, -- NOT NULL ? iva double precision DEFAULT 12.0, CONSTRAINT uni7 -- pick your contraint name UNIQUE (fila, factura, articulo, precio, talla, color, estado) );约束强制实现7列的唯一性 - 如果您实际需要它。
关于UNIQUEPRIMARY KEY约束(评论中的每个请求):

建议的表格设计:

...
LEFT   JOIN articulos_factura_venta r ON r.afv_id = f.afv_id
                                     AND r.estado & 16 <> 0
LEFT   JOIN articulos_factura_venta v ON v.afv_id = f.afv_id
                                     AND v.estado & 8 <> 0
...

然后可以将查询简化为:

{{1}}

答案 1 :(得分:1)

这是一个被称为链式外连接的问题。首先执行LEFT OUTER JOIN NULL之后,它会为右表中与左表不匹配的列创建NULL值。然后,当您将INNER JOIN值加上LEFT JOIN之后,这些行就会消失,就像您从未在第一时间进行外部联接一样。

有两种解决方案:

  1. 一旦开始JOIN,所有后续LEFT必须为FULLINNER JOIN
  2. 更好的选择是首先执行所有RIGHT JOIN并执行表格 想成为OUTER JOIN
  3. 的最后一个

    此外,当您LEFTRIGHT WHERE时,将ON CLAUSE条件移至{{1}通常是个好主意而不是WHERE子句。这是一个非常棘手的问题,但要查看FILTER条件和JOIN条件之间的区别,以及它们何时应放在WHERE vs ON子句中。