从基于另一个数组的数组中删除行

时间:2018-10-14 23:04:49

标签: php mysql sql

我完全迷住了,尝试了在SO上找到的其他解决方案,但没有任何效果。这是我的问题:

我有两个表,它们的结构完全不同。一个表用于USERS,另一个表用于BLOCKS。目标是从“用户”搜索中删除出现在“表”中的所有项目。

我曾尝试通过使用NOT IN的SQL查询来实现这一点,但这仅排除了其中一项。

我也在PHP中尝试了array_diff,但是在用户搜索结果中仍然看到被阻止的用户。

我不知道表结构是否必须匹配或者我的SQL是否太复杂。有指导吗?

表结构

> +----------+---------+-----------+
|username  |zipcode  |birthdate  |
+----------+---------+-----------+
|tester55  |72758    |1999-09-09 |
+----------+---------+-----------+
|tester86  |60608    |1983-05-10 |
+----------+---------+-----------+
|iosuser1  |10011    |1975-12-19 |
+----------+---------+-----------+
|iosuser5  |10011    |1975-12-21 |
+----------+---------+-----------+
|tester150 |10511    |1975-12-21 |
+----------+---------+-----------+


Blocks table
+----------+---------+-----------+
|blocker   |blockeduser
+----------+---------+-----------+
|tester86  |tester55 |          |
+----------+---------+-----------+
|iosuser5  |tester55 |         |
+----------+---------+-----------+
|tester150 |tester55 |         |
+----------+---------+-----------+

Zip Code table
+----------+---------+-----------+
|zipcode   |city
+----------+---------+-----------+
|72758     |Rogers   |          |
+----------+---------+-----------+
|60608     |Chicago  |         |
+----------+---------+-----------+

编辑:根据来自@TomC的反馈更新查询

    SELECT
    *
FROM
    (
    SELECT
        zipcodes.zip,
        zipcodes.city,
        zipcodes.state,
        users.id,
        users.username,
        users.ava,
        users.gender,
        users.race,
        users.headline,
        users.marital,
        users.height,
        users.bodytype,
        users.religion,
        users.education,
        users.occupation,
        users.politics,
        users.kids,
        users.wantkids,
        users.favdrink,
        users.drink,
        users.smoke,
        users.interests,
        users.aboutme,
        users.seekingGender,
        users.seekingdistance,
        users.seekingrace,
        users.seekingmarital,
        users.seekingminage,
        users.seekingmaxage,
        users.seekingminheight,
        users.seekingmaxheight,
        users.seekingbodytype,
        users.seekingreligion,
        users.seekingeducation,
        users.seekingoccupation,
        users.seekingpolitics,
        users.seekingkids,
        users.seekingwantkids,
        users.seekingdrink,
        users.seekingsmoke,
        users.birthdate,
        YEAR(CURRENT_TIMESTAMP) - YEAR(users.birthdate) -(
            RIGHT(CURRENT_TIMESTAMP, 5) < RIGHT(users.birthdate, 5)
        ) AS age,
        3959 * ACOS(
            COS(RADIANS(zipcodes.latitude)) * COS(RADIANS(center.latitude)) * COS(
                RADIANS(zipcodes.longitude) - RADIANS(center.longitude)
            ) + SIN(RADIANS(zipcodes.latitude)) * SIN(RADIANS(center.latitude))
        ) AS distance
    FROM
        users AS seeker
    JOIN zipcodes AS center
    ON
        center.zip = seeker.zip
    JOIN users ON seeker.zip = users.zip
    JOIN zipcodes ON zipcodes.zip = users.zip
    WHERE
        seeker.username = 'tester55' AND seeker.username <> users.username AND users.gender = seeker.seekingGender AND seeker.gender = users.seekingGender AND users.seekingmarital LIKE seeker.seekingmarital AND users.bodytype LIKE seeker.seekingbodytype AND users.religion LIKE seeker.seekingreligion AND users.education LIKE seeker.seekingeducation AND users.occupation LIKE seeker.seekingoccupation AND users.politics LIKE seeker.seekingpolitics AND users.kids LIKE seeker.seekingkids AND users.wantkids LIKE seeker.seekingwantkids AND users.drink LIKE seeker.seekingdrink AND users.smoke LIKE seeker.seekingsmoke AND users.race LIKE seeker.seekingrace AND seeker.seekingminheight <= users.height AND seeker.seekingmaxheight >= users.height AND users.birthdate >= DATE_SUB(
            NOW(), INTERVAL seeker.seekingmaxage YEAR) AND users.birthdate <= DATE_SUB(
                NOW(), INTERVAL seeker.seekingminage YEAR) AND NOT EXISTS(
                SELECT
                    *
                FROM
                    blocks
                WHERE
                    where blocks.blockeduser=seeker.username and blocks.blocker=users.username
            )
            ) selections
        WHERE
            distance < selections.seekingdistance
        ORDER BY
            distance

2 个答案:

答案 0 :(得分:1)

您不必声明表具有完全不同的结构,这就是数据库的整体思想。您可以按照@EmaniAzevedo的建议使用左联接,但是您需要根据需要检查两个列,或者使用不存在的联接。

我更喜欢不存在,因为我认为它更清楚。

static class User {
  ...
}

编辑:正如您现在添加的查询一样,该查询不存在,应简单地作为附加子句使用,并使用AND来添加该子句。我也看不到您为什么使用HAVING,我认为那也应该是AND。

第二个编辑:这是您整个查询,除去了令人困惑的括号。现在,它从寻找用户开始,在同一zip中找到所有其他用户,然后找到所有其他匹配用户。可以使用别名用户表来执行此操作,而不必使用嵌套查询。

顺便说一句,它会检查用户位于阻止程序表的两边-如果那不正确,请进行相应的修改。

select * from users 
where not exists(
    select * from blocks where Users.username = Blocks.blocker or users.username=Blocks.blockeduser
)

编辑:使用您的原始样本数据(包括表defs和插入),上述的一个非常简化的版本。我将所有样本用户更新为相同的zip,并将其用作唯一条件。如果这对您不起作用,请确保被阻止的用户确实正确匹配-例如,没有尾随空格。

select * from (
SELECT  zipcodes.zip, zipcodes.city, zipcodes.state,
        users.id, users.username, users.ava, users.gender, users.race, users.headline, users.marital, users.height, users.bodytype, users.religion, users.education, 
        users.occupation, users.politics, users.kids, users.wantkids, users.favdrink, users.drink, users.smoke, users.interests, users.aboutme, users.seekingGender, 
        users.seekingdistance, users.seekingrace, users.seekingmarital, users.seekingminage, users.seekingmaxage, users.seekingminheight, users.seekingmaxheight, 
        users.seekingbodytype, users.seekingreligion, users.seekingeducation, users.seekingoccupation, users.seekingpolitics, users.seekingkids, users.seekingwantkids, 
        users.seekingdrink, users.seekingsmoke, users.birthdate, 
        YEAR(CURRENT_TIMESTAMP) - YEAR(users.birthdate) - (RIGHT(CURRENT_TIMESTAMP, 5) < RIGHT(users.birthdate, 5)) as age, 
        3959 * acos(cos(radians(zipcodes.latitude)) *
                cos(radians(center.latitude)) *
                cos(radians(zipcodes.longitude ) -
                    radians(center.longitude)) +
                sin(radians(zipcodes.latitude)) *
                sin(radians(center.latitude))) AS distance 
from users as seeker
join zipcodes as centre on centre.zip=seeker.zip
JOIN users ON seeker.zip = users.zip
join zipcodes on zipcodes.zip=users.zip
where seeker.username = 'tester55' and seeker.username<>users.username AND users.gender = seeker.seekingGender AND seeker.gender=users.seekingGender
    AND users.seekingmarital LIKE seeker.seekingmarital AND users.bodytype LIKE seeker.seekingbodytype AND users.religion LIKE seeker.seekingreligion 
    AND users.education LIKE seeker.seekingducation and users.occupation LIKE seeker.seekingoccupation AND users.politics LIKE seeker.seekingpolitics 
    AND users.kids LIKE seeker.seekingkids AND users.wantkids LIKE seeker.seekingwantkids AND users.drink LIKE seeker.seekingdrinker 
    AND users.smoke LIKE seeker.seekingsmoker AND users.race LIKE seeker.seekingrace AND seeker.seekingminheight <= users.height AND seeker.seekingmaxheight >= users.height 
    AND users.birthdate >= DATE_SUB(NOW(), INTERVAL seeker.seekingmaxage YEAR) AND users.birthdate <= DATE_SUB(NOW(), INTERVAL seeker.seekingminage YEAR)
    and not exists(
        select * from blocks where blocks.blocker=users.username and blocks.blockeduser=seeker.username
    )
) selections
where distance < selections.seekingdistance
ORDER BY distance

结果:(已阻止所有阻塞tester55的用户)

create table users (username varchar(20),zipcode varchar(10),birthdate date)
insert users values ('tester55','10011','1999-09-09')
,('tester86','10011','1983-05-10')
,('iosuser1','10011','1975-12-19')
,('iosuser5','10011','1975-12-21')
,('tester150','10011','1975-12-21')

create table Blocks(blocker varchar(20),blockeduser varchar(20))
insert Blocks values ('tester86','tester55'),('iosuser5','tester55'),('tester150','tester55')

create table ZipCode(zipcode varchar(10), city varchar(20))
insert zipcode values ('72758','Rogers'),('60608','Chicago')

select users.*
from users seeker
join users on users.zipcode=seeker.zipcode and users.username<>seeker.username
where seeker.username='tester55'
and not exists(select * from blocks where blocks.blocker=users.username and blocks.blockeduser=seeker.username)

答案 1 :(得分:0)

假定此结构正确:

MariaDB [test]> SELECT * FROM `Users`;
+----------+---------+------------+
| username | zipcode | birthdate  |
+----------+---------+------------+
| tester55 |   72758 | 1999-09-09 |
| tester86 |   60608 | 1983-05-10 |
| iosuser1 |   10011 | 1975-12-19 |
| iosuser5 |   10011 | 1975-12-21 |
+----------+---------+------------+
4 rows in set (0.00 sec)

MariaDB [test]> SELECT * FROM `Blocks`;
+----------+-------------+
| blocker  | blockeduser |
+----------+-------------+
| tester86 | tester55    |
| iosuser5 | tester55    |
+----------+-------------+
2 rows in set (0.00 sec)

您可以使用以下查询:

MariaDB [test]> SELECT `Users`.* FROM `Users` LEFT JOIN `Blocks` ON `Users`.`username` = `Blocks`.`blocker` WHERE `Blocks`.`blocker` IS NULL;
+----------+---------+------------+
| username | zipcode | birthdate  |
+----------+---------+------------+
| tester55 |   72758 | 1999-09-09 |
| iosuser1 |   10011 | 1975-12-19 |
+----------+---------+------------+
2 rows in set (0.00 sec)