tags:

views:

81

answers:

4

I have a table with 2 columns:

nid realm
1   domain_id
1   domain_site
2   domain_id
3   domain_id

I want every entry to have 1 entry for domain id, and 1 for domain site. So I want to end up with:

nid realm
1   domain_id
1   domain_site
2   domain_id
2   domain_site
3   domain_id
3   domain_site

If I was doing this in PHP, I'd just foreach through the whole list and insert the extra line whenever it didn't exist. Unfortunately I only have PHPmyAdmin access to this DB. Is there a way to do this in straight SQL?

(If it makes a difference: The table has about 3000 rows currently, of which I think about 2000 will need the extra line inserted. Also, this is a one-time thing so it does not need to be optimized/uber-slick.)

A: 

I think this will do it, but I don't have a place to test it right now and I'm used to Sql Server rather than MySQL:

INSERT INTO `table`
SELECT id.nid, r.realm
FROM (SELECT nid FROM `table` GROUP BY nid) id
CROSS JOIN (SELECT realm FROM `table` GROUP BY realm) r
LEFT JOIN `table` t ON t.nid=id.nid AND t.realm=r.realm
WHERE t.realm IS NULL
Joel Coehoorn
A: 
insert into MyTable
(nid, realm)
select nid, 'domain_id'
from MyTable m where not exists (
    select 1 
    from MyTable
    where MyTable.nid = m.nid and realm = 'domain_id'
)
union all
select nid, 'domain_site'
from MyTable m where not exists (
    select 1 
    from MyTable
    where MyTable.nid = m.nid and realm = 'domain_site'
)
RedFilter
+2  A: 
INSERT IGNORE INTO `table`
SELECT `alt1`.`nid`, `alt2`.`realm`
FROM `table` AS `alt1`, `table` AS `alt2`
chaos
ooh, shiny IGNORE keyword
Jacob
That IS shiny!! I don't know what it says about me that I don't even understand this code, but I used it anyway! And it worked! (I backed up first. :)
Eileen
Glad you like it. :) It's doing something that under most circumstances would be very bad, a join with no conditions; I don't know what the academic term for it is, but I think of it as an "explosive join", because it results in all possible combinations of the two tables. Here, it all works out fine because you're inserting into a table with a unique constraint, so you just get the unique combinations that you care about, and the `IGNORE` makes any duplicate combinations fall out.
chaos
chaos, a cross join is the term you are looking for
HLGEM
Oh, is that all? Okay, thanks. (My surprise is because of course I've seen the term around, but I hadn't thought of it in connection with this unconstrained form, since all the cross joins I ever saw or wrote had linking conditions in the `WHERE` clause.)
chaos
OK wait, I said it worked but I spoke too soon! My test run inserted the row to the right nid, but set the "realm" as "0". (Which is OK because then I just did UPDATE domain_access SETrealm = "domain_site" WHERE realm = "0" . ) So what do I do to make it set realm correctly?
Eileen
Oops. I guess you had `realm` values of 0 in the original table; I was basing the query on your original table looking like the one you posted. If you added `WHERE alt2.realm` to my query that should stop it from putting in any zeroes.
chaos
A: 

If you have a UNIQUE constraint over (nid, realm), you could do this:

INSERT IGNORE INTO nidTable (nid, realm)
  SELECT nid, 'domain_site'
  FROM nidTable WHERE realm = 'domain_id';
Bill Karwin