Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/mysql/66.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Php 如何检查mysql表中多行中与每行中唯一数据关联的值_Php_Mysql - Fatal编程技术网

Php 如何检查mysql表中多行中与每行中唯一数据关联的值

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

我正在使用php开发一个记录管理应用程序。我设计了一个名为records的表,其中包含字段
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)?它通常不太适合与关系数据库一起使用