14

I have two tables with very similar structures.

Universidades
nombre | contenido | becas | fotos etc etc etc
Internados
nombre | todo | becas | fotos etc etc etc

I want to write an SQL statement that will select the nombre from both of them and return it as an array only when it matches. From what I have seen UNION SELECT seems to be the way to do this. I added WHERE on the end and I think this is where its going wrong. So far I am receiving the first row of the first table.

What am I typing wrong?

$db = new PDO(DB_DSN, DB_USERNAME, DB_PASSWORD);
$data = $db->prepare("SELECT nombre FROM internados UNION SELECT nombre FROM universidades WHERE nombre = ?");
$data->execute(array($nombre));

apologies, I want to retrive one result from these two tables. Namees in the nombre column are all individual and different in both tables

4

2 回答 2

26

在我们解决问题之前要指出的一个问题是 a 中的每个查询UNION都是不同的,并且需要自己的WHERE子句。唯一适用于UNION整体的子句是ORDER BY. 因此,您的查询需要进行一些调整:

SELECT nombre
FROM dbo.internados
WHERE nombre = ? -- the added line
UNION
SELECT nombre
FROM dbo.universidades
WHERE nombre = ?
;

其次,如果您希望两个表都具有相同的nombre值(这并不完全清楚,但我猜这是对的),那么这将不起作用,因为如果在一表nombre中找到该值,它只会返回一个。解决这个问题的最好方法可能是只做一个连接:

SELECT I.nombre
FROM
   dbo.internados I
   INNER JOIN dbo.universidades U
      ON I.nombre = U.nombre
WHERE
   I.nombre = ?
   AND U.nombre = ? -- perhaps not needed, but perhaps helpful
;

我不能 100% 确定我完全理解您在寻找什么,所以如果我错过了标记,请说出来。

你可以这样JOINUNION

  • JOIN:水平连接行
    • 根据条件匹配它们
    • 创建新
    • 不完全创建行,因为所有数据都来自现有行,但是当条件与另一个输入中的多行匹配时,它将从一个输入复制一行。如果两个输入都有重复,则它将一个输入的行数乘以另一个输入的匹配行数。
    • 如果根本没有匹配条件(想想CROSS JOIN),那么您可以获得一个笛卡尔积,它是一个输入中的每一行与另一个输入中的每一行匹配。
    • 当使用OUTERjoin-- LEFT, RIGHT, FULL-- 如果来自内部输入(或任何一个输入FULL)的行不匹配另一个,NULLs 将被放置到另一个输入的列中。
  • UNION:垂直堆叠行
    • 通常,创建新
    • 没有使用条件,没有真正的匹配
    • UNION本身 (not UNION ALL) 将删除重复的行,即使一个输入没有行

请注意,UNION可以修改它来完成这项工作,尽管这并不理想:

SELECT nombre
FROM (
   SELECT nombre
   FROM dbo.internados
   WHERE nombre = ?
   UNION ALL
   SELECT nombre
   FROM dbo.universidades
   WHERE nombre = ?
) N
GROUP BY nombre
HAVING Count(*) = 2
;

通过这种方式,我们确保有两个值。请注意,这假定每个表中不能有两个同名。如果这是真的,则需要做更多的工作才能使该UNION方法发挥作用。

于 2013-06-13T17:03:18.433 回答
6

大多数时候 aunion可以通过加入来实现:

SELECT nombre 
  FROM internados 
UNION 
SELECT nombre 
  FROM universidades 
 WHERE nombre = ?

最好是:

SELECT nombre
  FROM internados i
  JOIN universidades u
    ON i.nombre = u.nombre
   AND nombre = ?

这更容易阅读。(您也可以使用JOIN语法,但我更喜欢普通的旧手动连接)。

但无论这是 aunion还是 a join,请始终记住两个表都在结果中合并:

nombre | todo | becas | fotos | ... | contenido | becas | ...

所以基本上,当你在 nombre 上设置条件时,你要么得到一个空集,要么得到你为查询提供的名称。但是,按照您编写并集的方式,只有第二组where应用了条件,而不是第一个。您应将条件放在工会的两个查询上:

SELECT nombre 
  FROM internados 
 WHERE nombre = ?
UNION 
SELECT nombre 
  FROM universidades 
 WHERE nombre = ?
于 2013-06-13T16:54:18.967 回答