Re: Building an SQL query
by AgentM (Curate) on Oct 19, 2000 at 21:19 UTC
|
Hmm. This is not the best way to organize a database. You may want to look into normalization. This will cut down on redundacy and maximize efficiency. Also, I can imagine that every time you want to use the data (for example in a CGI script), you are forced to use a split. If you retrieve the normalized data in the first place, you'll probably see a performance boost. That said, what's with the question? SQL has specific keywords that deal with insert and delete. You may look them up in the DBI tutorial.
| [reply] |
Re: Building an SQL query
by runrig (Abbot) on Oct 19, 2000 at 21:19 UTC
|
The 'best' way would be to have two tables, a 'user' table and an 'address' table, with a common column ('username' or perhaps a 'user_id' field), then your problem would be simple. Then you could easily insert, delete, and update addresses, and there would be no limit on the number of addresses you could store.
That being said, with the way you describe the table, you'd need to select the 'addresses' of a user, split them up, add, delete, or update the appropriate one, paste the addresses back together, then update the user record. Sounds like a pain to me, but its what you'd have to do.
Update: A simple split/join procedure: # Add/Update or delete an address
my %hsh;
my @arr=split /\s*,\s*/, $addresses;
@hsh{@arr}=@arr;
# Add/Update an address
$hsh{'Joe Schmoe joe@schmoe.com'}='Joseph Schmoe joseph@schmoe.com';
# Delete an address
delete $hsh{JoeBob Schmoe joebob@scmoe.com};
$addresses = join ", ", values %hsh;
| [reply] [d/l] |
Re: Building an SQL query
by swiftone (Curate) on Oct 19, 2000 at 21:16 UTC
|
Are you asking for SQL statement advice, or the perl code to access them?
SQL: "update {TABLENAME} set {FIELDNAME}={NEW VALUE} where {CONDITIONS}"
Perl: read up on DBI and the DBD modules for your database.
Update: Just noticed that you have more than one entry in your addresses field. Bad practice, it limits you. You should have multiple records:
| DESPAIR | Iamhere@place.org |
| DESPAIR | andheretoo@nother.place.org |
| [reply] |
Re: Building an SQL query
by cadfael (Friar) on Oct 19, 2000 at 22:05 UTC
|
I think I would start off by deciding what data are 1:1 --
that is what should you put into the main table. For example:
create table person_data (
id_no int NOT NULL,
surname varchar(100) NOT NULL,
given_name varchar(100) NOT NULL
)
And then tables consisting of 1:many data such as
email addresses, phone numbers, etcetera. For example:
create table person_email (
id_no int NOT NULL
email_address varchar(100) NOT NULL
)
I recommend the use of a surrogate key (i.e. the id_no)
because the person's name (the natural key) is subject to
change. By using a stable surrogate key, you avoid having
to change the key because it stays with the record until
deleted.
By using a 1:many table, you have the flexibility of
dealing with multiple phone numbers or email addresses. By
placing each in a separate row, you avoid the situation where
you have multiple values in one field, which is a violation
of First Normal Form, and of course by extension, Third
Normal Form.
Why worry about normality? Because the power of a
relation database lies in the elimination of redundancy,
thereby increasing data integrity, and reducing time spent
in maintenance. And as a previous reply pointed out, when
you get to the point where you are using DBI::DBD to extract
the information, you have fewer steps you need to take with
Perl.
Good Luck
-----
"Computeri non cogitant, ergo non sunt" | [reply] [d/l] [select] |
Re: Building an SQL query
by arturo (Vicar) on Oct 19, 2000 at 21:50 UTC
|
How can I pull this peice of data out of all the addresses If I select *
from addresses?
According to your description you can't select * from addresses, because "addresses" is a column, not a table.
If what you want to do is search for an address that matches a pattern, then the SQL you want is something like this:
SELECT addresses FROM table_name WHERE addresses LIKE '%pattern%'
One worry here is that this SELECT is not guaranteed to return a unique value.
An alternative is to grab *all* the addresses into (say) an array in Perl and use grep to grab the ones you want. This will have the same problem as above, however.
my @addresses;
my $sth= $db->prepare('SELECT addresses FROM table_name') or die "SQL
+error: $DBI::errstr\n";
$sth->execute();
while (my $row = $sth->fetchrow) {
push @addresses, $row;
}
my @matches = grep { /pattern/ } @addresses;
Let me add my voice to the throng that says "NORMALIZE" though. It will make your life *soooooo* much easier.
Philosophy can be made out of anything. Or less -- Jerry A. Fodor | [reply] [d/l] [select] |
Re: Building an SQL query
by swiftone (Curate) on Oct 19, 2000 at 22:22 UTC
|
I would of course be remiss in my duties as a Perl Monk if I didn't mention that you can write a perl script to create a new, normalized database from this one. No effort beyond writing the script required. You can use some of the code above that accesses the data you have now to be the bulk of the script, and just add some SQL statements.
| [reply] |
Re: Building an SQL query
by Anonymous Monk on Oct 19, 2000 at 21:35 UTC
|
My apologies for posting a somewhat ambiguous question. I guess you can say my confusion more or less lies within the realm of what to do after I fetch all the data in a particular addresses column. It would definitely be easier if there were two different tables, one for username, and one for all the corresponding name and address values, but for now, lets assume that this is the way it has to be. Okay, a quick example: Lets say a user, named "Blah" wants to edit a particular address ( Joe Schmoe joe@scmoe.com ). How can I pull this peice of data out of all the addresses If I select * from addresses? | [reply] |
|
|
Okay, so your question is basically "How do I edit a string of comma delimited email addresses"?
One way is to separate the data. Split the string on commas (assumes no email address have commas in them), then split each of those elements into outside <> and inside <>
Edit the data, then rebuild your string.
This seems to work:
#!/usr/bin/perl -w
use strict;
my $test='A <a@bob.com>, B <B@b.org>, Calcutta <O@thehorror.net>';
my @names = split /\s?,\s?/, $test; #split apart
$_ = [split /\s(?=<)/, $_] for (@names); #make array refs of each
# Above happily learned from merlyn
foreach my $name (@names) {
foreach (@{$name}){
print "--$_--";
}
print "\n";
}
It outputs:
--A----<a@bob.com>--
--B----<B@b.org>--
--Calcutta----<O@thehorror.net>--
And of course, you can edit that as you wish. Of course, if you KNOW one element, it'd be better to use a hash
#!/usr/bin/perl -w
use strict;
my $test='A <a@bob.com>, B <B@b.org>, Calcutta <O@thehorror.net>';
my %names = split /,\s|\s(?=<)/, $test; #split apart
foreach my $name (keys (%names)) {
print "$name==$names{$name}\n";
}
This also works, and allows you to access (and modify) $names{Joe Schmoe}
Rebuilding your original list is even easier after you modify it.
my @names;
while (my ($key, $value) = each %names){
push @names, "$key $value";
}
print join ', ',@names;
Note that all of the above code assumes that:
- No email addresses or names have commas
- No names or email address have < beyond the wrapper around email addresses
- Your list always has the entries separated with a comma then a space
- Your names are always separated from your email addresses by a space.
| [reply] [d/l] [select] |
Re: Building an SQL query
by AgentM (Curate) on Oct 19, 2000 at 21:57 UTC
|
Ew! Each row in your data set should contain a UNIQUE_ID (called various things in different DBengines). That's what you want to clean up first. using that, you might allow the user to be able to refine his search. next, you'll want to think about exactly what it is you want. If you say that you want a unique answer, then just grab the first one you want and ignore the others. of course, if you respond to the user with only one, it may be the wrong one. The current design of your database makes it very inefficient in a search for an address (dbload- going up?) I guess your solution is the best for the situation, though, either perl or the dbengine is going be doing lots of busywork since you have a poorly designed db!
| [reply] |
Re: Building an SQL query
by despair (Initiate) on Oct 19, 2000 at 21:59 UTC
|
Righteous. You guys are awesome. Thanks a mil. | [reply] |
Re: Building an SQL query
by despair (Initiate) on Oct 20, 2000 at 00:05 UTC
|
Geez, I can't seem to match this pattern correctly:
$somename <$someaddress>
| [reply] [d/l] |
|
|
$somename = qr/[\w\.\s]+/;
$someaddress = qr/[\w\.+]+@[\w\.]+/;
if (/($somename) <($someaddress)>/) {
print "Got a name of '$somename'\n";
print "Got address of '$someaddress'\n";
}
Note that this is generally not the best way of looking for e-mail addresses in plain text. The relevant RFC's describe very complex rules for valid SMTP addresses, and it is going to be very difficult for you to build a quality set of regular expressions that will be able to pull these out of text. You may be interested in Email::Find to locate e-mail addresses, and Email::Valid to validate a sample string as an e-mail address (does not search for it, just validates an assumed address).
On the other hand, if your intent is to build a pattern out of those two variables, to see if a particular line matches someone's name and e-mail address, you could easily do something like this:
$somename = 'David Nesting';
$someaddress = 'david@example.com';
$_ = 'David Nesting <david@example.com>';
if (/^$somename <$someaddress>$/) {
print "Yep, this one is $somename!\n";
}
I hope this helps. Otherwise, please provide more information. | [reply] [d/l] [select] |
|
|
The code I posted above split on a look-ahead for the first < (Which means it assumes your "name" fields don't have that. Note everything
that Fastolfe said about Email addresses is true, they're quite difficult to validate/match for all possible cases.
| [reply] |