Gossamer Forum
Home : General : Databases and SQL :

SQL DISTINCT Help!

Quote Reply
SQL DISTINCT Help!
Hello all-

I am currently revamping a database containing user account information. I have created a SQL view which displays UserID (nchar 35) and an Account (float 9). Simple enough-- however, here's the tricky part: there are multiple accounts for the same UserID. How can I group all the accounts for the same user in one record? (Note: the maximum number of accounts per user is 8) Any help would be greatly appreciated. Thanks in advance!
Quote Reply
Re: [suzypen] SQL DISTINCT Help! In reply to
You should make the user id column non unique so you can enter the same id more than once with a different group name, eg:

Code:
UserID Group
1 Test
1 FooBar
1 Foob
2 FooBar
3 Test

Last edited by:

Paul: Mar 18, 2003, 8:24 AM
Quote Reply
Re: [Paul] SQL DISTINCT Help! In reply to
The ID column is not unique, since it is in the table multiple times. That's the problem. The table has over 2000 rows containg information. An example would be:


UserID Account
suzypen2 1234567
suzypen2 3215789
suzypen2 9274618
lime#w2 1027839


The request that I'm being asked to do it to retrieve the information for the particular user in this format:


UserID Account1 Account2 Account3
susypen2 1234567 3215789 9274618
lime#w2 1027839


Any suggestions for this?
Quote Reply
Re: [suzypen] SQL DISTINCT Help! In reply to
SELECT * FROM Table WHERE UserID = 'suzypen2'

...is all that's need if I understand you correctly.
Quote Reply
Re: [Paul] SQL DISTINCT Help! In reply to
I need a recap for all users in one table for auditing purposes. (Ok, I just ran a user count. The total amount of users it about 6,000 and the total number of accounts is about 14,000!!! It's insane!) In brief- I am trying to get a recap listing the userID once and all their corresponding accounts (limit 8) in one row. There shoudl be about 6,000 rows (1 row for each user). Does this make any sense?
Quote Reply
Re: [suzypen] SQL DISTINCT Help! In reply to
Yes it does. You need to use a programming language like perl I expect, to handle this. I don't think you can do everything you want with just an SQL query.

You'd probably want to do a SELECT DISTINCT(UserID) From Table and then loop the results and within the loop perform a select on the Group column using the user id for the current loop iteration - that would grab all the groups for each user - you would then store them in a perl structure like a hash.

Last edited by:

Paul: Mar 18, 2003, 9:24 AM
Quote Reply
Re: [Paul] SQL DISTINCT Help! In reply to
Ouch. Thanks for you help. Do you think that Access could handle this type of query?
Quote Reply
Re: [suzypen] SQL DISTINCT Help! In reply to
Unfortunately I don't have great familiarity with Access :(

If you want a perl version I can create something for you. I probably made it sound a lot harder than it is.
Quote Reply
Re: [Paul] SQL DISTINCT Help! In reply to
It sounded really confusing especially since I am not perl-savvy. I'm more of a .net/asp/php/sql gal.
If only the whole world was Oracle... Smile

I really appreciate your help. Those are the only two fields that I need and the parameters are specified above.
Quote Reply
Re: [suzypen] SQL DISTINCT Help! In reply to
I am very interested in you solution. NOt only will it *hopefully* fix the problem I cannto seem to solve, but it will introduce me to a new way of solving things. I look forward to seeing this! YOu're the best!
Quote Reply
Re: [suzypen] SQL DISTINCT Help! In reply to
Sorry for the delay...I'll assume for the example that the database handle has already been created...let me know if you need help with that.

Code:
my @keep = ();

# Select all unique user ids.
my $sth1 = $dbh->prepare("SELECT DISTINCT(UserID) FROM Table");

# Select the group ids for each user id.
my $sth2 = $dbh->prepare("SELECT GroupID From Table WHERE UserID = ?");

$sth1->execute();

# Loop all the selected user ids.
while (my $row = $sth->fetchrow) {

# Now execute the query selecting all group ids.
$sth2->execute($row);

# Save the group ids.
my @gids = map { $_->[0] } @{$sth2->fetchall_arrayref()};

# Store all group ids for this user in a perl data structure.
push @keep, { $row => \@gids };
}

$sth1->finish;
$sth2->finish;

So theoretically you then have all your data. You can see the contents by using:

require Data::Dumper;
print Data::Dumper::Dumper(\@keep);

...it should look something like:

Code:
$VAR = [
{
'suzypen2' => [
'1234567',
'3215789',
'9274618'
]
},
{
'lime#w2' => [
'1027839'
]
}
];


That is untested and may be totally wrong :)
Quote Reply
Re: [suzypen] SQL DISTINCT Help! In reply to
If you are on Oracle....as Database then

Step1

create a table temp1 will foll structure

SQL> desc temp1
Name Null? Type
------------------------------- -------- ----
USERID VARCHAR2(35)
ACCOUNT1 NUMBER

This Table Is Of Same Structure of your existing table (except the data type .... you could keep your datatype)

Create a new table say temp which will have 8 more cols for account1....account8

create all the unique userid records in temp by following sql statement

insert into temp(userid) select userid from temp1

SQL> desc temp
Name Null? Type
------------------------------- -------- ----
USERID VARCHAR2(35)
ACCOUNT1 NUMBER
ACCOUNT2 NUMBER
ACCOUNT3 NUMBER
ACCOUNT4 NUMBER
ACCOUNT5 NUMBER
ACCOUNT6 NUMBER
ACCOUNT7 NUMBER
ACCOUNT8 NUMBER





Now The PL/SQL

Code:
declare

cursor c1 is select userid,account1 from temp1
order by userid;
x varchar(35);
x1 varchar(35):='xx';
y number;
y1 number:=0;

begin

open c1;

Loop

Fetch c1 into x,y;

exit when c1%notfound;


if x != x1
Then
y1:=1 ;
x1:=x;
else
y1:=nvl(y1,0)+1;

End If;

if y1 = 1 then
update temp set account1 = y
where userid = x;
End If;

if y1 = 2 then
update temp set account2 = y
where userid = x;
End If;

if y1 = 3 then
update temp set account3 = y
where userid = x;
End If;

if y1 = 4 then
update temp set account4 = y
where userid = x;
End If;

if y1 = 5 then
update temp set account5 = y
where userid = x;
End If;

if y1 = 6 then
update temp set account6 = y
where userid = x;
End If;

if y1 = 7 then
update temp set account7 = y
where userid = x;
End If;

if y1 = 8 then
update temp set account8 = y
where userid = x;
End If;


End Loop;

Close c1;

End;

This Is A Crude way of Getting what you want...

Professionaly i would have done it by using Pro*C using the prepare statement for dynamic sql so that i would have avoided using 8 update statements.

But Hope Your Purpose Is Solved Coz code is Tested The Out Put Is As Follows

SQL> select * from temp1;

USERID ACCOUNT1
----------------------------------- ---------
suzypen2 1234567
suzypen2 3215789
suzypen2 9274618
lime#w2 1027839
suzypen2 4356543
suzypen2 9745451
suzypen2 7589053
lime#w2 6748906
lime#w2 4874325
lime#w2 8902347
orange 2345678
orange 2233445
orange 7676767

after executing the PL/SQL prog ...The Output of temp table is as desired by you.

SQL> select * from temp;

USERID ACCOUNT1 ACCOUNT2 ACCOUNT3 ACCOUNT4 ACCOUNT5 ACCOUNT6 ACCOUNT7 ACCOUNT8
----------------------------------- --------- --------- --------- --------- --------- --------- --------- ---------
orange 2345678 2233445 7676767
lime#w2 1027839 6748906 4874325 8902347
suzypen2 1234567 3215789 9745451 7589053 4356543 9274618


Few Records were added for testing purpose to your sample data

Smile

Last edited by:

anup123: Mar 23, 2003, 3:37 PM
Quote Reply
Re: [anup123] SQL DISTINCT Help! In reply to
I think you are all making this much more difficult (and slow) than necessary. For formatting purposes, you need to do two queries, but they are both very simple. I come from a Java background, so maybe I don't know the limitations of asp/php, but I'm pretty sure you are not required to have all your data pre-formated in your SQL result set!

Code:
select count(*) as cols from Table group by UserID order by 1 desc limit 1;

This gets you the number of columns across your page that you will need to create your HTML table's column headers.

Then, you just get your data:

Code:
select UserID, Account from Table order by 1,2;

Then, as you go through your result set, whenever you encounter a new UserID, you create a new row in your table.

Or, if you want to remove your business logic from your presentation logic, use the following SQL to get the number of rows you will need:

Code:
select count(distinct UserID) from Table;

This, along with the first query, will get you the dimensions to create a 2D Array that can hold all your data. You can then populate it with the second query from above, and pass it to your presentation tier.

Very simple, no repetitive DB connections for each user, and no temp table with thousands of updates.

Here is some (untested) simplistic jsp code. No error checking or closing of statements and connections, but you get the idea...

Code:
<html><header><title>All Users, All Accounts</title></header>
<body>
<table>
<tr>
<td>UserID</td>
<%
...Get your DB connection and Statement...
rs = stmt.execute("select count(*) as cols from Table group by UserID order by 1 desc limit 1");
int maxCols = -1;
if(rs.next())
{
maxCols = rs.getInt(1);
}
for(int col=1; col <= maxCols; ++col)
{
%> <td>Account <%=col%></td>
<%
}
String lastUser = "";
String thisUser = "";
rs2 = stmt.execute("select UserID, Account from Table order by 1,2");
while(rs2.next())
{
thisUser = rs2.getString(1);
if(!(thisUser.equals(lastUser)))
{
lastUser = thisUser;
// We have a new user, so close off the previous row and start a new one
%> </tr><tr>
<td><%=thisUser%></td>
<%
}
%> <td><%=rs.getInt(2)%></td>
<%
}
%> </tr>
</table>
</body></html>
Quote Reply
Re: [JavaSavant] SQL DISTINCT Help! In reply to
I like the way that you went about to solve this problem.

I was wondering what parameters are specific to JSP, since I have to use ASP.

Thanks!