我正在使用以下sql语句
SELECT * FROM inventory LEFT OUTER JOIN invUpdate ON (inventory.vin = invUpdate.vin)
它为我提供了正确的记录数,但仅显示来自invUpdate表的信息。我使用以下php变量
$row_Recordset1['vin']
显示基本网页上的记录。虽然它在页面下方列出了103条记录,但实际上只显示了invUpdate页面中的4条记录。其余的都是空的。我是否需要更改我的sql语句,还是应该使用其他变量?
答案 0 :(得分:2)
我认为问题是查询返回了两列名为vin
的列。并且这两者都被分配到相同的数组元素$row['vin']
。我相信这是你遇到的问题的症结所在。
解决这个问题的一种方法是抛弃 SELECT *
并明确列出要返回的表达式。由于inventory
和invUpdate
表都包含名为vin
的列,因此这两个列都位于SELECT *
返回的表达式列表中。
如果您需要返回两者,则使用别名分配这些表达式中的一个(或两个),以区别于另一个。例如:
SELECT inventory.vin AS vin
, inventory.somecol AS somecol
, invUpdate.vin AS uvin
, SUBSTR(inventory.foo1,1,1) AS f
, ...
FROM ...
获取一行后,您可以访问两个vin
列返回的值,并通过指定的别名(即分配给表达式的列名称)引用它们。
$val1 = $row['vin'];
$val2 = $row['uvin'];
这不是唯一的方法。但它是我喜欢的方法,明确列出我想要返回的表达式,并明确指定别名。它是用于SQL语句中更复杂表达式的常用模式。同样的模式也适用于简单的陈述。
<强>后续
这远远超出了原来提出的问题。在回应评论时,关于&#34;覆盖&#34;当inventory
中找到匹配的行时,来自invUpdate
的列的值与invUpdate
的列值相对应...
就个人而言,如果我想这样做,我宁愿在SQL语句中这样做。 (其他人有不同的意见,有不同意见的空间。我更喜欢有一个声明,返回我实际想要显示的结果,而没有很多额外的列。
不知道你的表格中有哪些列,(SELECT *
并没有给那些可怜的读者留下太多信息),假设这两列中的列名相同。< / p>
鉴于连接谓词vin
= vin
,我们知道vin
中的invUpdate
在找到匹配的行时不能为NULL。
SELECT IF(u.vin IS NULL,i.vin,u.vin) AS vin
该表达式表示,如果在invUpdate
中找不到匹配的行,则从vin
表返回inventory
,否则从vin
表返回invUpdate
。这相当于更符合ANSI标准:
SELECT CASE WHEN u.VIN IS NULL THEN i.vin ELSE u.vin END AS vin
如果我们需要来自invUpdate
到&#34的列的所有的值,请覆盖&#34;来自inventory
的所有列的值(当在invUpdate
中找到匹配的行时,
SELECT u.vin IS NOT NULL AS `update_found`
, IF(u.vin IS NULL,i.vin ,u.vin ) AS `vin`
, IF(u.vin IS NULL,i.fee ,u.fee ) AS `fee`
, IF(u.vin IS NULL,i.fi ,u.fi ) AS `fi`
, IF(u.vin IS NULL,i.fo ,u.fo ) AS `fo`
, IF(u.vin IS NULL,i.fum ,u.fum ) AS `fum`
, u.updated_date AS `updated_date`
, SUBSTRING(i.vin,1,5) AS `first_five`
FROM inventory i
LEFT
JOIN invUpdate u
ON u.vin = i.vin
ORDER BY i.vin
是的,这是一个更复杂的SQL语句。但我可以测试一下。我可以验证它是否正常工作,返回我需要的集合,与程序的其余部分分开。这样我的程序中的代码就会少得多。
关注
问:让我说每张表中有32列。如果我想以这种方式展示它们,我是否必须为每列写入IF(u.id IS NULL,i.col,u.col)?
A:不幸的是,是的。
但是,如果我有32列要争用,我会编写一个SQL语句来获取我需要的SQL语句的一部分...使用SQL生成SQL。
作为一个单独的步骤(不是作为程序的一部分),来自mysql命令行客户端的SQLyog,或者其他......
我发表了类似这样的声明:
SELECT CONCAT(' , IF(u.vin IS NULL,i.`', c.column_name, '`,u.`', c.column_name, '`) AS `', c.column_name, '`') AS stmt
FROM information_schema.columns c
WHERE c.table_name = 'mytable'
AND c.table_schema = 'mydb'
ORDER BY c.ordinal_position
代替&#34; mytable&#34;和&#34; mydb&#34;使用表名和数据库名称,并返回如下结果:
stmt
----------------------------------------------------------------------------
, IF(u.vin IS NULL,i.`id`,u.`id`) AS `id`
, IF(u.vin IS NULL,i.`ext_name`,u.`ext_name`) AS `ext_name`
, IF(u.vin IS NULL,i.`src_name`,u.`src_name`) AS `src_name`
, IF(u.vin IS NULL,i.`database_id`,u.`database_id`) AS `database_id`
, IF(u.vin IS NULL,i.`protocol`,u.`protocol`) AS `protocol`
, IF(u.vin IS NULL,i.`location`,u.`location`) AS `location`
, IF(u.vin IS NULL,i.`device_name`,u.`device_name`) AS `device_name`
, IF(u.vin IS NULL,i.`vendor_name`,u.`vendor_name`) AS `vendor_name`
, IF(u.vin IS NULL,i.`model_name`,u.`model_name`) AS `model_name`
然后我会复制该结果,并将其粘贴到编辑器中,因此我不必输入所有这些列名。
答案 1 :(得分:0)
作为一种完全不同的方法...如果inventory
和invUpdate
具有相同的列,列名,数据类型等,我们想要的是从{{1}返回所有行以及来自invUpdate
的{{1}} ...
然后我们可以使用反连接模式从inventory
返回行,然后将其(使用invUpdate
)与来自{{1}的行合并}。
这样的事情:
inventory
两个查询的列数和数据类型(与UNION ALL结合使用)必须匹配。 (就匹配而言,列名称并不重要。结果集中列的名称来自第一个查询。)
这个答案没有具体解决所提出的问题;但我相信这是OP实际上想要的结果集。
与我之前的答案中的方法一样,这会将复杂性转移到SQL语句,从而大大简化了代码。
还有其他SQL模式(反连接除外)将返回等效结果。例如,使用UNION ALL
谓词。例如,第一个查询(在invUpdate
之前)也可以写成:
( SELECT i.vin
, i.col2
, i.col3
FROM inventory i
LEFT
JOIN invUpdate iu
ON iu.vin = i.vin
WHERE iu.vin IS NULL
)
UNION ALL
( SELECT u.vin
, u.col2
, u.col3
FROM invUpdate u
)
ORDER BY vin
(我的偏好是反加入,除非我能从其他替代方案中获得更好的效果,例如NOT EXISTS
或UNION ALL
无论哪种方式,对于大型集合,缺少适当的索引都会对性能产生负面影响。