Thread: How can I do this?

How can I do this?

From
"Boget, Chris"
Date:

I'm still in the process of converting my MySQL DB
to PG.  I've redone the table schemas so that they
are normal form.
In trying to move data from one table to another, I
need the corresponding relevant data from 2 other
tables.  The table that I'm moving the data INTO has
the following schema

trader_id   | integer  | not null default 0
card_name   | integer  | not null default 0
total_have  | integer  | not null default 0
is_tradable | smallint | default 0
record_num  | bigint   | not null default nextval('public.trader_haves_record_num_seq'::text)
Indexes: trader_haves_pkey primary key btree (record_num),
         trader_haves_card_name_key btree (card_name),
         trader_haves_trader_id_key btree (trader_id)
Foreign Key constraints:
$1 FOREIGN KEY (trader_id) REFERENCES logins(record_num) ON UPDATE CASCADE ON DELETE CASCADE,
$2 FOREIGN KEY (card_name) REFERENCES cards_type(record_num) ON UPDATE CASCADE ON DELETE CASCADE

In the old table, trader_id had the person's name and
card_name had the name of the card.  However, now, those
fields are referencing the relevant fields in the logins
and cards_type tables, respectively.  As you can see
above. :p
Since I can't just copy the data straight over, I need
to get the appropriate record nums for the data in the
old columns.  This is the query that I tried to build:

SELECT ( SELECT cards_type.record_num FROM cards_type WHERE cards_type.card_name LIKE ( substr( trader_haves_old.card_name, 1, 9 ) || '%' )), trader_haves_old.total_have, ( SELECT logins.record_num FROM logins WHERE logins.name = trader_haves_old.trader ), trader_haves_old.available from trader_haves_old;

However, that's not working because the subselects are
returning more than one row.  Ok, that's fine I guess.
But I don't know any other way I can do this?  How can
I create a query to return the data I need?  I'm still
relatively unfamiliar and am still getting used to sub
selects because MySQL doesn't have them.

Any help would be very much appreciated!

thnx,
Chris

Re: How can I do this?

From
Manfred Koizar
Date:
On Wed, 8 Jan 2003 18:37:13 -0600 , "Boget, Chris" <chris@wild.net>
wrote:
>I'm still in the process of converting my MySQL DB
>to PG.  I've redone the table schemas so that they
>are normal form.
>
>SELECT ( SELECT cards_type.record_num FROM cards_type WHERE
>cards_type.card_name LIKE ( substr( trader_haves_old.card_name, 1, 9 ) ||
>'%' )), trader_haves_old.total_have, ( SELECT logins.record_num FROM logins
>WHERE logins.name = trader_haves_old.trader ), trader_haves_old.available
>from trader_haves_old;

Chris, why do you want to match on only the first nine characters of
card_name?  A typical normalization job looks like:

-- record_num is supplied by DEFAULT clause
INSERT INTO cards_type(card_name)
SELECT DISTINCT card_name
  FROM trader_haves_old;

-- record_num is supplied by DEFAULT clause
INSERT INTO logins(name)
SELECT DISTINCT trader
  FROM trader_haves_old;

INSERT INTO trader_haves(card_id, total_have, trader_id, available)
SELECT c.record_num, o.total_have, l.record_num, o.available
  FROM trader_haves_old o
       INNER JOIN cards_type c ON c.card_name = o.card_name
       INNER JOIN logins l ON l.name = o.trader;

HTH.
Servus
 Manfred

Re: How can I do this?

From
"Chris Boget"
Date:
> >SELECT ( SELECT cards_type.record_num FROM cards_type WHERE
> >cards_type.card_name LIKE ( substr( trader_haves_old.card_name, 1, 9 ) ||
> >'%' )), trader_haves_old.total_have, ( SELECT logins.record_num FROM logins
> >WHERE logins.name = trader_haves_old.trader ), trader_haves_old.available
> >from trader_haves_old;
> Chris, why do you want to match on only the first nine characters of card_name?

I'm doing that because of the kinds of problems that crop up when you don't
use normalization - the values in the card_name field in the 2 seperate tables
don't always match up.  Sometimes there is, say (as an analogy), a first and
last name and sometimes there is only a first name.  So by grabbing the first
9 characters of the column for this transfer from the old to the new table, I'll
be able to get the proper record number (from cards_type) for 99+% of the
cards.
Sadly, the MySQL database wasn't normalized and I've been running into a
lot of roadblocks (mainly from the fact that I'm still learning PG) in converting
it over.

> A typical normalization job looks like:

Right.  If all the names matched.

> INSERT INTO trader_haves(card_id, total_have, trader_id, available)
> SELECT c.record_num, o.total_have, l.record_num, o.available
>   FROM trader_haves_old o
>        INNER JOIN cards_type c ON c.card_name = o.card_name
>        INNER JOIN logins l ON l.name = o.trader;

I'll try (a slight modified version of) this when I get home.
Thanks!

Chris


Re: How can I do this?

From
Manfred Koizar
Date:
On Thu, 9 Jan 2003 07:08:15 -0600, "Chris Boget" <chris@wild.net>
wrote:
>> Chris, why do you want to match on only the first nine characters of card_name?
>
>I'm doing that because of the kinds of problems that crop up when you don't
>use normalization - the values in the card_name field in the 2 seperate tables
>don't always match up.  Sometimes there is, say (as an analogy), a first and
>last name and sometimes there is only a first name.  So by grabbing the first
>9 characters of the column for this transfer from the old to the new table, I'll
>be able to get the proper record number (from cards_type) for 99+% of the
>cards.

So if you have

card_id | card_name
--------+--------------
    277 | 123456789abc
    727 | 123456789bbc
    772 | 123456789bca

which card_id do you want to select for trader_haves_old.card_name =
'123456789bbc'?

>Sadly, the MySQL database wasn't normalized and I've been running into a
>lot of roadblocks (mainly from the fact that I'm still learning PG) in converting
>it over.

While you are still unfamiliar with the new DB, don't make several
steps at once.  Strictly separate the tasks of
a) importing data,
b) cleaning up structures (normalization),
c) cleaning up data.

You already have done (a), because there is a table trader_haves_old.
If you do step (b) like suggested, you end up with data that are not
worse than now.  You can always look for similar names later:

SELECT count(*), substring(card_name, 1, 9)
  FROM cards_type
 GROUP BY substring(card_name, 1, 9)
HAVING count(*) > 1;

... and then eliminate unwanted card_names one by one (if there are
only a few):

SELECT card_id, card_name
  FROM cards_type
 WHERE card_name LIKE '123456789%';

UPDATE trader_haves
   SET card_id = 277
 WHERE card_id IN (727, 772);

DELETE FROM cards_type
 WHERE card_id IN (727, 772);

Good luck!
Servus
 Manfred

Re: How can I do this?

From
"Chris Boget"
Date:
> So if you have
> card_id | card_name
> --------+--------------
>     277 | 123456789abc
>     727 | 123456789bbc
>     772 | 123456789bca
> which card_id do you want to select for trader_haves_old.card_name =
> '123456789bbc'?

That's a perfectly valid point.  And as I said, I'd be able to get the proper
record number for 99+%.  Happily, there aren't situations like the one you
describe.  The names of the cards are almost all distinguishable within the
first 9 characters. That's why I chose it as my aribitrary value. :p

> >Sadly, the MySQL database wasn't normalized and I've been running into a
> >lot of roadblocks (mainly from the fact that I'm still learning PG) in converting
> >it over.
> While you are still unfamiliar with the new DB, don't make several steps at once.
> Strictly separate the tasks of
> a) importing data,

Already done in temporary holding tables.

> b) cleaning up structures (normalization),

Done.  These are the tables I'm trying to move the data to.

> c) cleaning up data.

Haven't done this.  Perhaps it would be a good idea to update the temp table with
the proper values before moving over the the actual table.  This would certainly
make things a heck of a lot easier!

> Good luck!

Thank you very much for your help and your advice!

Chris