Sql 有没有一种方法可以在不创建笛卡尔积的情况下从两个表中获取数据?

Sql 有没有一种方法可以在不创建笛卡尔积的情况下从两个表中获取数据?,sql,sql-server,tsql,Sql,Sql Server,Tsql,在我们的数据库中,客户可以有任意数量的驾驶员、任意数量的车辆、任意数量的存储位置、这些位置的任意数量的建筑物、任意数量的评论,等等。我需要一个返回客户所有信息的查询,现在该查询类似于: SELECT * FROM Customer c INNER JOIN Driver d ON c.ID = d.CustomerID INNER JOIN Vehicle v ON c.ID = v.CustomerID 客户拥有的产品越多,结果就越大,并且会呈指数增长,因为这里正在创建笛卡尔积。3个驱动程序

在我们的数据库中,客户可以有任意数量的驾驶员、任意数量的车辆、任意数量的存储位置、这些位置的任意数量的建筑物、任意数量的评论,等等。我需要一个返回客户所有信息的查询,现在该查询类似于:

SELECT *
FROM Customer c
INNER JOIN Driver d ON c.ID = d.CustomerID
INNER JOIN Vehicle v ON c.ID = v.CustomerID
客户拥有的产品越多,结果就越大,并且会呈指数增长,因为这里正在创建笛卡尔积。3个驱动程序,3个向量创建9行,与实际数据相比,这是一个非常小的示例。实际上,我们有10个不同的表,每个客户可以容纳任意多的行。标准是每个客户每个表至少有2-7行。我们已经返回了多达60000000多行(10个不同表中各有6个项目,6^10=60466176),为了我们的目的,如果我们能够将每个表中的6行粘在一起,总共6行将为我们提供所需的所有数据

因此,在较小的示例中,如果一个客户有2辆车和3名驾驶员,而另一个客户有2辆车和1名驾驶员,我希望结果集如下所示:

CustomerID  | DriverID | VehicleID
1           | 1        | 1
1 (or NULL) | 2        | 2
1 (or NULL) | NULL     | 3
2           | 3        | 4
2 (or NULL) | 4        | NULL
相反,我们将CustomerID上的每个表连接在一起的查询如下所示:

CustomerID | DriverID | VehicleID
1          | 1        | 1
1          | 1        | 2
1          | 1        | 3
1          | 2        | 1
1          | 2        | 2
1          | 2        | 3
2          | 3        | 4
2          | 4        | 4
真的,我想做的只是:

SELECT * FROM Driver
SELECT * FROM Vehicle
因为我们对数据所做的只是在行中循环并格式化文档中的信息。列出所有驾驶员,然后列出所有车辆。在我们不需要的时候进行这种疯狂的大连接是没有意义的,但它只是一个任意的要求,它必须返回一个结果集中的所有数据,这些数据来自一个顽固的上级,他拒绝听从理智。因为列是不同的,所以不能合并。我只是希望有一种方法可以把它们水平地粘在一起,而不是垂直地粘在一起


另外,我使用的是Microsoft SQL Server。

这是一个丑陋的黑客行为,但您知道正确的解决方案正如您所说:

SELECT * FROM Driver
SELECT * FROM Vehicle
相反,您可以使用union查询并清空其他表中的列,只需使用设置列的类型和名称的查询启动它,并使用假coldition,这样它就不会返回行:

SELECT 1 AS DriverID, "" AS DriverName, 1 AS VehicleID, "" AS VehicleName WHERE 1=0 
UNION SELECT DriverID, DriverName, NULL, NULL FROM Driver
UNION SELECT NULL, NULL, VehicleID, VehicleName FROM Driver

非常非常糟糕的代码!继续与你的上司合作,以获得更好的解决方案。

这是一个丑陋的黑客行为,但你知道你的正确解决方案正如你所说的:

SELECT * FROM Driver
SELECT * FROM Vehicle
相反,您可以使用union查询并清空其他表中的列,只需使用设置列的类型和名称的查询启动它,并使用假coldition,这样它就不会返回行:

SELECT 1 AS DriverID, "" AS DriverName, 1 AS VehicleID, "" AS VehicleName WHERE 1=0 
UNION SELECT DriverID, DriverName, NULL, NULL FROM Driver
UNION SELECT NULL, NULL, VehicleID, VehicleName FROM Driver

非常非常糟糕的代码!继续与上司合作,以获得更好的解决方案。

以下是我的做法。而不是:

SELECT *
FROM Customer c
INNER JOIN Driver d ON c.ID = d.CustomerID
INNER JOIN Vehicle v ON c.ID = v.CustomerID
我正在做:

WITH CustomerCTE AS
(
  SELECT 1 ROW_NUM, ID
  FROM Customer
),
DriverCTE AS
(
  SELECT ROW_NUMBER() OVER (PARTITION BY CustomerID ORDER BY ID) ROW_NUM, *
  FROM Driver
),
VehicleCTE AS
(
  SELECT ROW_NUMBER() OVER (PARTITION BY CustomerID ORDER BY ID) ROW_NUM, *
  FROM Vehicle
)
SELECT *
FROM CustomerCTE c
FULL OUTER JOIN DriverCTE d ON c.ID = d.CustomerID AND c.ROW_NUM = d.ROW_NUM
FULL OUTER JOIN VehicleCTE v ON d.CustomerID = v.CustomerID AND d.ROW_NUM = v.ROW_NUM
ORDER BY
CASE WHEN c.ID IS NOT NULL THEN c.ID ELSE
  CASE WHEN d.CustomerID IS NOT NULL THEN d.CustomerID ELSE
    v.CustomerID
  END
END,
CASE WHEN c.ROW_NUM IS NOT NULL THEN c.ROW_NUM ELSE
  CASE WHEN d.ROW_NUM IS NOT NULL THEN d.ROW_NUM ELSE
    v.ROW_NUM
  END
END
现在,如果客户有3名司机和3辆车,我会得到3排,而不是9排。这使它看起来好像每个司机都与3辆车中的1辆相关,但实际上并非如此。同样,这是一个糟糕的设计,但是有必要减少返回的行数,因为我受到了不合理的限制

这看起来比webturner的答案需要做更多的工作,但在我的实际情况中,我必须连接10个不同的表和超过500列,这样做比显式命名所有500列并用NULL填充每个表中的所有剩余列要少得多


不过,这对大多数人来说可能没有多大用处。在大多数情况下,如果你正在做这样的事情,你可能需要重新考虑你的设计,但在某些情况下,你可能别无选择。

我就是这样做的。而不是:

SELECT *
FROM Customer c
INNER JOIN Driver d ON c.ID = d.CustomerID
INNER JOIN Vehicle v ON c.ID = v.CustomerID
我正在做:

WITH CustomerCTE AS
(
  SELECT 1 ROW_NUM, ID
  FROM Customer
),
DriverCTE AS
(
  SELECT ROW_NUMBER() OVER (PARTITION BY CustomerID ORDER BY ID) ROW_NUM, *
  FROM Driver
),
VehicleCTE AS
(
  SELECT ROW_NUMBER() OVER (PARTITION BY CustomerID ORDER BY ID) ROW_NUM, *
  FROM Vehicle
)
SELECT *
FROM CustomerCTE c
FULL OUTER JOIN DriverCTE d ON c.ID = d.CustomerID AND c.ROW_NUM = d.ROW_NUM
FULL OUTER JOIN VehicleCTE v ON d.CustomerID = v.CustomerID AND d.ROW_NUM = v.ROW_NUM
ORDER BY
CASE WHEN c.ID IS NOT NULL THEN c.ID ELSE
  CASE WHEN d.CustomerID IS NOT NULL THEN d.CustomerID ELSE
    v.CustomerID
  END
END,
CASE WHEN c.ROW_NUM IS NOT NULL THEN c.ROW_NUM ELSE
  CASE WHEN d.ROW_NUM IS NOT NULL THEN d.ROW_NUM ELSE
    v.ROW_NUM
  END
END
现在,如果客户有3名司机和3辆车,我会得到3排,而不是9排。这使它看起来好像每个司机都与3辆车中的1辆相关,但实际上并非如此。同样,这是一个糟糕的设计,但是有必要减少返回的行数,因为我受到了不合理的限制

这看起来比webturner的答案需要做更多的工作,但在我的实际情况中,我必须连接10个不同的表和超过500列,这样做比显式命名所有500列并用NULL填充每个表中的所有剩余列要少得多


不过,这对大多数人来说可能没有多大用处。在大多数情况下,如果您正在执行类似的操作,您可能需要重新考虑您的设计,但在某些情况下,您可能没有选择。

您真的需要将数据作为单独的行返回吗?之后你用它干什么?您可以使用一个操作员将驾驶员聚合到一个伪列、另一个列中的车辆等,并按客户ID进行分组,否?您如何知道驾驶员1仅与车辆1关联?每个驾驶员都可以与每辆车关联,这就是您的查询所显示的内容。是否有其他字段来描述其他链接(即驱动1获取车辆1)火花,驾驶员和车辆没有关联。它们都与客户相关。我不关心哪些车辆与哪些驾驶员在同一排,我只关心每个车辆和每个驾驶员都在结果中。
内部联接
不是笛卡尔积@NullUserException:
内部联接
不是数学定义。在SQL中,
内部联接
是一种特殊的笛卡尔乘积,例如,可以使用乘积(
交叉联接
)和限制(
其中
)重新编写
内部联接
)。考虑到CODD的代数有积和限制,但没有<代码>连接< /代码>运算符,但仍然是关系完备的(重命名操作符除外)。code>CROSS JOIN不是笛卡尔乘积,因为它不生成对(虽然我不知道如何称呼生成的是什么!),是的,这只是对语义的挑剔:)您真的需要作为单个行返回的数据吗?之后你用它干什么?您可以使用一个操作符将驾驶员聚合到一个伪列中,即车辆