Sql 将表与其自身联接,并使用位操作筛选每个表中的行
我有下表Sql 将表与其自身联接,并使用位操作筛选每个表中的行,sql,postgresql,database-design,left-join,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 NUL
-- 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
[1] 该表包含数千行,但我只对这些行感兴趣,即
factura==28239
这是一个称为链式外部联接的问题。首先执行一些LEFT-OUTER-JOIN
,它会为右表中与左表不匹配的列创建NULL
值。然后,当您将这些NULL
值与之后的内部联接
进行联接时,这些行将消失,就好像您一开始从未进行过外部联接一样
有两种解决方案:
左连接
所有后续的连接
必须是左连接
或完全连接
内部联接,然后执行所需的表
想成为外部最后一个右连接
另外,在执行
外部联接时,无论是左
还是右
,通常最好将WHERE
子句条件移动到ON
子句中,而不是将WHERE
子句中。这是一个非常棘手的问题,但请查找筛选条件和加入条件之间的区别,以及它们何时应放置在WHERE
vsON
子句中。长话短说,可能是这样的:
SELECT f.factura
, f.fila
, f.cantidad
, r.cantidad
, v.cantidad
, f.estado
FROM articulos_factura_venta f
-- JOIN articulos a ON a.codigo = f.articulo -- just noise
-- JOIN tallas t ON t.codigo = f.talla
-- JOIN colores c ON c.codigo = f.color
JOIN empleados e ON e.codigo = f.vendedor
LEFT JOIN articulos_factura_venta r ON r.fila = f.fila
AND r.color = f.color
AND r.talla = f.talla
AND r.origen = f.origen
AND r.factura = f.factura
AND r.articulo = f.articulo
AND r.vendedor = f.vendedor
AND r.estado & 16 <> 0
LEFT JOIN articulos_factura_venta v ON v.fila = f.fila
AND v.color = f.color
AND v.talla = f.talla
AND v.origen = f.origen
AND v.factura = f.factura
AND v.articulo = f.articulo
AND v.vendedor = f.vendedor
AND v.estado & 8 <> 0
WHERE f.factura = 28239
AND f.estado & 4 <> 0
ORDER BY f.estado;
另一个棘手的细节:
JOIN empleados e ON e.codigo = f.vendedor
但是f.vendedor
可以NULL
。您是否打算从结果中删除带有f的所有行。vendedor为NULL
?因为这就是join所做的
我对articulos
、tallas
和colors
的三个连接进行了注释。FK列为非空
,联接只会消耗时间,并且您不使用任何列
表定义
超过7列的主键约束是一个糟糕的想法。昂贵而笨拙。添加代理主键-我建议使用serial
列:
如果您确实需要,您仍然可以使用UNIQUE
约束在7列集合上强制唯一性。
关于和约束(根据注释中的请求):
建议的表格设计:
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)
);
创建表articulos\u factura\u venta(
afv_id序列主键--选择您的列名
一个整数不为空,
cantidad整数不为空,
颜色整数不为空,
整数不为空,
estado整数默认值2不为空,
factura整数不为空,
articulo整数不为空,
precio整数不为空,
fecha date NOT NULL默认值now()::日期,
奥利根整数,
vendedor整数,
anulado布尔值默认值为false,--不为NULL?
iva双精度默认值12.0,
约束uni7——选择您的约束名称
独特(fila、factura、articulo、precio、talla、color、estado)
);代码>
然后可以将查询简化为:
...
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
...
。。。
在r.afv\U id=f.afv\U id上左关节连接
r.estado和160
v.afv\U id=f.afv\U id上的左关节连接
v.estado和80
...
缺少一些约束条件
。。。但约束对于构建正确的查询至关重要。请给出完整的图片-您从psql中的\d articulos\u factura\u venta
中得到了什么。有趣的是,这可能意味着我不能使用使用。我不确定您使用的SQL的哪个版本使用了USING子句,以及为什么将内部联接移到顶部会不起作用。但无论如何,你可以扩展ON子句,使用完整的ON x.col=y.col样式语法。看到另一个答案,海报删除了使用
的,因为不可能在它后面添加r.estado&16 0
,我想,问题。我想现在我也明白了原因。@iharob:这意味着一行在一个联接表中有两个匹配项,这可能不应该发生……这是因为两行中都设置了一些位,4
几乎在每一行中,因此,添加f.estado&8=0和f.estado&16=0实际上是有意义的
...
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
...