Re: Help writing SQL statement in PHP script
- From: gary.l.simms@xxxxxxxxx
- Date: Sun, 18 May 2008 03:21:32 -0700 (PDT)
Tim Roberts wrote:
Jerry Stuckle <jstucklex@xxxxxxxxxxxxx> wrote:
This table is 100% 1NF - but it has duplicates in the (userid, groupid)
entries:
userid groupid permission
1 1 read
1 1 write
1 1 delete
1 2 read
1 3 read
You are absolutely correct. I *suspect* the difference in opinion here
comes down to terminology; many people do not consider a database to be
"normalized" until it is 3NF, and the table above is not 3NF.
Not quite correct, because Jerry's query still fails on this table
structure. This is easily demonstrated by this SQL example:
DROP TABLE IF EXISTS test;
CREATE TABLE test (
userid int not null,
groupid int not null,
permission char(6) not null,
primary key (groupid, userid, permission)
);
INSERT INTO test VALUES
(1, 1, 'read'),
(1, 1, 'write'),
(1, 1, 'delete'),
(1, 2, 'read'),
(1, 2, 'write'),
(1, 2, 'delete');
SELECT t1.groupid
FROM test AS t1
LEFT JOIN test AS t2
ON t1.userid = t2.userid
WHERE t1.groupid = 1 AND t2.groupid = 2;
His query returns:
9 rows in set (0.00 sec)
Jerry's query returned 9 rows, but there only 6 in the original table.
This is a serious inconsistency. His oft-repeated claim that his query
works with duplicates is clearly false. In another example that was
posted here, his query produced 200 million results in a table with
40,000 records. The more data you have, the more infeasible this
becomes.
Peter's approach works correctly however. The original query targeted
a binary relation posted by the OP. If you want to alter the problem
to have a ternary, quaternary, or higher dimension relation as in
Jerry's latest and greatest table design, then you simply use COUNT
DISTINCT like so:
SELECT userid
FROM test
WHERE groupid IN (1, 2)
GROUP BY userid
HAVING COUNT(DISTINCT userid, groupid) = 2;
However, what if you want to test for membership in not just 2 groups,
but 10, 100 or 1,000? That's easy to do with Peter's solution by
creating a simple function:
function group_intersection($group_ids)
{
$matches = array();
if (count($group_ids)) {
$set = join(', ', $group_ids);
$query = "SELECT userid FROM test WHERE
groupid IN ($set) GROUP BY userid HAVING
COUNT(DISTINCT userid, groupid) = " .
count($group_ids);
$db = getMdb2();
$matches = $db->extended->getCol($query);
}
return $matches;
}
$group_ids = range(1, 1000);
print_r(group_intersection($group_ids));
Let's see Jerry's solution do that... It can't, because it's
restricted to 2 groups only! That is a second serious deficiency in
his design, which doesn't pass muster in the real world where you
could have hundreds or thousands of groups defined.
--
Gary L. Simms
gary.l.simms at gmail.com
.
- References:
- Re: Help writing SQL statement in PHP script
- From: Mike Lahey
- Re: Help writing SQL statement in PHP script
- From: Jerry Stuckle
- Re: Help writing SQL statement in PHP script
- From: Corey Jansen
- Re: Help writing SQL statement in PHP script
- From: vkayute
- Re: Help writing SQL statement in PHP script
- From: Jerry Stuckle
- Re: Help writing SQL statement in PHP script
- From: Mitch Sherman
- Re: Help writing SQL statement in PHP script
- From: Jerry Stuckle
- Re: Help writing SQL statement in PHP script
- From: oxision
- Re: Help writing SQL statement in PHP script
- From: Jerry Stuckle
- Re: Help writing SQL statement in PHP script
- From: Tim Roberts
- Re: Help writing SQL statement in PHP script
- Prev by Date: How to call Win32 API functions ?
- Next by Date: Re: php to get date and time separately into MySQL?
- Previous by thread: Re: Help writing SQL statement in PHP script
- Next by thread: Re: Help writing SQL statement in PHP script
- Index(es):
Relevant Pages
|