Php 如何检查mysql表中多行中与每行中唯一数据关联的值
我正在使用php开发一个记录管理应用程序。我设计了一个名为records的表,其中包含字段Php 如何检查mysql表中多行中与每行中唯一数据关联的值,php,mysql,Php,Mysql,我正在使用php开发一个记录管理应用程序。我设计了一个名为records的表,其中包含字段id,recordname,recordvalue,recordid。例如,如果一条记录包含3个数据firstname,lastname,gender。3数据(John Doe男性、Jane Doe女性和Sherlock Holmes男性)插入下表- ----+-------------+--------------+----------- id | recordname | recordvalue
id
,recordname
,recordvalue
,recordid
。例如,如果一条记录包含3个数据firstname
,lastname
,gender
。3数据(John Doe男性、Jane Doe女性和Sherlock Holmes男性)插入下表-
----+-------------+--------------+-----------
id | recordname | recordvalue | recordid
----+-------------+--------------+-----------
1 | firstname | John | 001
2 | lastname | Doe | 001
3 | gender | Male | 001
4 | firstname | Jane | 002
5 | lastname | Doe | 002
6 | gender | Female | 002
7 | firstname | Sherlock | 003
8 | lastname | Holmes | 003
9 | gender | Male | 003
----+-------------+--------------+-----------
我的问题是什么时候在表中插入一条新记录,我需要检查记录是否有重复。这意味着可以随时复制不同记录的任何字段,但不能复制具有相同记录值的所有字段。从前面的示例记录来看,具有值John Doe Femal、Jane Doe Male、Sherlock Doe Male等的记录是可以的,但再次插入John Doe Male是不应该的,它将给出一个错误
如何使用PHP轻松实现这一点
提前谢谢
我的问题是什么时候在表中插入一条新记录,我需要检查记录是否有重复
您的“记录”与此处的正常数据库记录(=一行)有所不同
这意味着可以随时复制不同记录的任何字段,但不能复制具有相同记录值的所有字段。从前面的示例记录来看,具有值John Doe Femal、Jane Doe Male、Sherlock Doe Male等的记录是可以的,但再次插入John Doe Male是不应该的,它将给出一个错误
因此,在您的案例中,多个记录的组合必须是唯一的
如何使用PHP轻松实现这一点
您可以选择first并查看是否已经得到了要插入的数据的结果,正如Yadav在回答中所建议的那样。但这将导致一个可能的TOCTTOU问题——为了避免这个问题,您必须将SELECT和INSERT封装到事务中
另一种方法是使用INSERT…SELECT语句。SELECT语句必须以这样一种方式表达,即它只在尚未找到值时返回要插入的值—计算匹配的记录,并使用必须只筛选那些提供正确记录数的记录(在您的示例中为三个)即可。我认为您应该修复您的表,它的设计非常糟糕。应该是这样的
table
--------------------------------------------
record_id | firstname | lastname | gender
然后,如果您只想在数据库中保留它,您可以使用一个唯一的索引(firstname、lastname、gender)来控制它
[编辑]
由于您无法更改数据库设计,而且它使用的是EAV结构,因此您可以使用下面的查询来实现所需的功能。如果您的条件中有或没有记录,则将返回此查询
SELECT a.recordvalue, b.recordvalue, c.recordvalue
FROM rec_eav a
INNER JOIN rec_eav b ON (b.recordid = a.recordid AND b.recordname = 'lastname' )
INNER JOIN rec_eav c ON (c.recordid = a.recordid AND c.recordname = 'gender' )
WHERE a.recordname = 'firstname'
AND a.recordvalue = 'John'
AND b.recordvalue = 'Doe'
AND c.recordvalue = 'Male'
运行类似于以下内容的查询:
select count(*) countmatch
from datatable
where concat(recordname,':',recordvalue) in
('firstname:John', 'lastname:Doe', 'gender:Male')
group by recordid
order by countmatch desc
limit 1
-如果返回的countmatch值为3,则拒绝新的John Doe男性记录,否则将其添加到表中
编辑:如果FrestNew、LaSTNEX和Abess一起唯一地标识一个记录,但是其他属性可能是稀疏的和/或任意填充的,那么您可能需要考虑一个混合模式——可能类似于这样的:
KeyTable
--------
firstname
lastname
gender
recordid
SELECT a.recordid
FROM test a
JOIN test b ON ( b.recordname = 'firstname' AND b.recordvalue = 'John' AND b.recordid = a.recordid)
JOIN test c ON ( c.recordname = 'lastname' AND c.recordvalue = 'Doe' AND c.recordid = a.recordid)
WHERE (a.recordname = 'gender' AND a.recordvalue = 'female')
eav_hell(entity*,attribute*,value)
* = (component of) PRIMRY KEY
-在firstname、lastname和gender的组合上使用唯一索引,在recordid上使用单独的唯一索引
DataTable
---------
-和现在一样,recordid上有一个外键。请注意,firstname、lastname和gender属性不应存储在此表中
当尝试添加firstname、lastname和gender的“新”组合时,尝试将它们添加到KeyTable中-如果插入被DBMS拒绝,则表示记录已经存在
在这种情况下,存储在DataTable上的recordname/recordvalue组合应始终包含一个recordid,该recordid链接到KeyTable上的有效recordid。您将需要如下内容:
KeyTable
--------
firstname
lastname
gender
recordid
SELECT a.recordid
FROM test a
JOIN test b ON ( b.recordname = 'firstname' AND b.recordvalue = 'John' AND b.recordid = a.recordid)
JOIN test c ON ( c.recordname = 'lastname' AND c.recordvalue = 'Doe' AND c.recordid = a.recordid)
WHERE (a.recordname = 'gender' AND a.recordvalue = 'female')
eav_hell(entity*,attribute*,value)
* = (component of) PRIMRY KEY
如果结果为空,则可以继续(如在我的示例中,如果将性别值更改为男性,则将返回一个recordid,因此此组合已存在)您可以尝试以下查询,如果返回了答案,则您已经有类似的数据。否则,它将返回0行:
select recordid from records
where recordvalue in ('John', 'Doe', 'Male')
group by recordid
having count(recordid) = 3
编辑:上面的查询可能会给出不止一个结果,正如@Xavjer所解释的,请尝试以下操作:
select * from
(
select
max(case when recordname="firstname" then recordvalue end) as firstname,
max(case when recordname="lastname" then recordvalue end) as lastname,
max(case when recordname="gender" then recordvalue end) as gender,
recordid
from records
group by recordid
) as record
where firstname='doe'
and lastname='john'
and gender='male'
如果你要使用一个EAV模型来存储数据,那么考虑这样的结构:
KeyTable
--------
firstname
lastname
gender
recordid
SELECT a.recordid
FROM test a
JOIN test b ON ( b.recordname = 'firstname' AND b.recordvalue = 'John' AND b.recordid = a.recordid)
JOIN test c ON ( c.recordname = 'lastname' AND c.recordvalue = 'Doe' AND c.recordid = a.recordid)
WHERE (a.recordname = 'gender' AND a.recordvalue = 'female')
eav_hell(entity*,attribute*,value)
* = (component of) PRIMRY KEY
请考虑一下那些被丢弃的糟糕数据类型。谢谢大家的支持。不管怎样,我已经找到了解决问题的办法。这很棘手,我不知道它有多有效。所以我把它贴在这里供专家评论。谢谢 我的问题是-我有一个EAV表,其中单个实体有多个属性和相应的值。我需要检查是否有人提交了带有某个记录值的表单,所有这些值都已作为另一个记录存在数据库中。例如,如果John Doe Male已在
recordid
001下的表中,则用户无法将John Doe Male另存为另一条记录,而是会给用户一条消息“记录已存在!”
我执行了一些查询-
foreach($submitted_values as $name => $value){
$r = mysql_query("SELECT DISTINCT `recordid` FROM `records` WHERE `recordname` = '$name' AND `recordvalue` = '$value'");
while($row = mysql_fetch_assoc($r)){
$assoc[$name][] = $row['recordid'];
}
}
因此,在$assoc
中,我得到了一个二维数组,该数组用字段名编制索引,并与一个匹配的recordid
数组相关联
然后我检查了$assoc
数组中是否有任何匹配的值,如果我得到一个非空数组,我确定在单个记录下有一个或多个提交值的重复
这个过程还帮助我告诉用户,有些值是部分匹配的。这对我来说非常有效
再次感谢大家浪费您宝贵的时间。我无法理解您的数据库结构,为什么要为firstname、lastname和genderi存储不同的记录您为什么要在表结构中使用这种方法(通常称为Entity attribute Value;简称EAV)?它通常不太适合与关系数据库一起使用