Home All Groups Group Topic Archive Search About
Author
29 Sep 2005 8:32 PM
Arpan
My application retrieves records from a SQL Server 7.0 DB table for
which I am using a stored procedure but while coding, I am not aware of
the no. of columns existing in that DB table. Neither am I aware of the
column names while coding. Also more columns can get added to the table
in the future.

What I want to do is retrieve the DISTINCT records from each column &
populate them in drop-down lists that will be finally displayed to the
user. For each column, there will be 1 drop-down list which will be
listing the DISTINCT records of that column. For e.g. if there are,
say, 15 columns, there will be 15 drop-down lists i.e. one drop-down
for each column. Had I known the column names while coding, the
following queries would have sufficed:

SELECT DISTINCT(Col1) FROM MyTable ORDER BY Col1
SELECT DISTINCT(Col2) FROM MyTable ORDER BY Col2
SELECT DISTINCT(Col3) FROM MyTable ORDER BY Col3
.............
.............

but since the column names are not known, the above won't work in my
case. I have to get the column names first. To do so, I am using the
INFORMATION_SCHEMA.COLUMNS view in my stored procedure to first get the
column names & then looping through the columns to get the DISTINCT
records from each of the columns. This is code snippet in my stored
procedure:

----------------------------------------
CREATE PROCEDURE GetRecords
AS
DECLARE
    @sql varchar(8000)

WHILE (SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE
TABLE_NAME='MyTable') IS NOT NULL
BEGIN
    SET @sql='SELECT DISTINCT(COLUMN_NAME) FROM MyTable WHERE COLUMN_NAME
IS NOT NULL ORDER BY COLUMN_NAME'
END
EXEC (@sql)
----------------------------------------

But when the above is executed in QA, as expected, it throws the
"Subquery returned more than 1 value. This is not permitted......"
error.

So how do I get the column names & then retrieve the DISTINCT records
from each column?

Thanks,

Arpan

Author
29 Sep 2005 8:52 PM
Alejandro Mesa
Try,


> WHILE (SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE
> TABLE_NAME='MyTable') IS NOT NULL

declare @ordinal_position int
declare @cn sysname

set @ordinal_position = 1

while @ordinal_position <= (select count(*) from information_schema.columns
where table_schema = 'dbo' and table_name = 'MyTable')
   begin
   select
      @cn = column_name
   from
      information_schema.columns
   where
      table_schema = 'dbo' and table_name = MyTable'
      and ordinal_position = @ordinal_position

   set @sql = 'SELECT DISTINCT(' + quotename(@cn) + ') FROM MyTable ORDER BY
' + quotename(@cn)

   exec sp_executesql @sql

   set @ordinal_postion = @ordinal_position + 1

   end
....


AMB

Show quote
"Arpan" wrote:

> My application retrieves records from a SQL Server 7.0 DB table for
> which I am using a stored procedure but while coding, I am not aware of
> the no. of columns existing in that DB table. Neither am I aware of the
> column names while coding. Also more columns can get added to the table
> in the future.
>
> What I want to do is retrieve the DISTINCT records from each column &
> populate them in drop-down lists that will be finally displayed to the
> user. For each column, there will be 1 drop-down list which will be
> listing the DISTINCT records of that column. For e.g. if there are,
> say, 15 columns, there will be 15 drop-down lists i.e. one drop-down
> for each column. Had I known the column names while coding, the
> following queries would have sufficed:
>
> SELECT DISTINCT(Col1) FROM MyTable ORDER BY Col1
> SELECT DISTINCT(Col2) FROM MyTable ORDER BY Col2
> SELECT DISTINCT(Col3) FROM MyTable ORDER BY Col3
> .............
> .............
>
> but since the column names are not known, the above won't work in my
> case. I have to get the column names first. To do so, I am using the
> INFORMATION_SCHEMA.COLUMNS view in my stored procedure to first get the
> column names & then looping through the columns to get the DISTINCT
> records from each of the columns. This is code snippet in my stored
> procedure:
>
> ----------------------------------------
> CREATE PROCEDURE GetRecords
> AS
> DECLARE
>     @sql varchar(8000)
>
> WHILE (SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE
> TABLE_NAME='MyTable') IS NOT NULL
> BEGIN
>     SET @sql='SELECT DISTINCT(COLUMN_NAME) FROM MyTable WHERE COLUMN_NAME
> IS NOT NULL ORDER BY COLUMN_NAME'
> END
> EXEC (@sql)
> ----------------------------------------
>
> But when the above is executed in QA, as expected, it throws the
> "Subquery returned more than 1 value. This is not permitted......"
> error.
>
> So how do I get the column names & then retrieve the DISTINCT records
> from each column?
>
> Thanks,
>
> Arpan
>
>
Author
29 Sep 2005 8:55 PM
Alejandro Mesa
The Curse and Blessings of Dynamic SQL
http://www.sommarskog.se/dynamic_sql.html


AMB

Show quote
"Alejandro Mesa" wrote:

> Try,
>
>
> > WHILE (SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE
> > TABLE_NAME='MyTable') IS NOT NULL
>
> declare @ordinal_position int
> declare @cn sysname
>
> set @ordinal_position = 1
>
> while @ordinal_position <= (select count(*) from information_schema.columns
> where table_schema = 'dbo' and table_name = 'MyTable')
>    begin
>    select
>       @cn = column_name
>    from
>       information_schema.columns
>    where
>       table_schema = 'dbo' and table_name = MyTable'
>       and ordinal_position = @ordinal_position
>
>    set @sql = 'SELECT DISTINCT(' + quotename(@cn) + ') FROM MyTable ORDER BY
> ' + quotename(@cn)
>
>    exec sp_executesql @sql
>
>    set @ordinal_postion = @ordinal_position + 1
>   
>    end
> ...
>
>
> AMB
>
> "Arpan" wrote:
>
> > My application retrieves records from a SQL Server 7.0 DB table for
> > which I am using a stored procedure but while coding, I am not aware of
> > the no. of columns existing in that DB table. Neither am I aware of the
> > column names while coding. Also more columns can get added to the table
> > in the future.
> >
> > What I want to do is retrieve the DISTINCT records from each column &
> > populate them in drop-down lists that will be finally displayed to the
> > user. For each column, there will be 1 drop-down list which will be
> > listing the DISTINCT records of that column. For e.g. if there are,
> > say, 15 columns, there will be 15 drop-down lists i.e. one drop-down
> > for each column. Had I known the column names while coding, the
> > following queries would have sufficed:
> >
> > SELECT DISTINCT(Col1) FROM MyTable ORDER BY Col1
> > SELECT DISTINCT(Col2) FROM MyTable ORDER BY Col2
> > SELECT DISTINCT(Col3) FROM MyTable ORDER BY Col3
> > .............
> > .............
> >
> > but since the column names are not known, the above won't work in my
> > case. I have to get the column names first. To do so, I am using the
> > INFORMATION_SCHEMA.COLUMNS view in my stored procedure to first get the
> > column names & then looping through the columns to get the DISTINCT
> > records from each of the columns. This is code snippet in my stored
> > procedure:
> >
> > ----------------------------------------
> > CREATE PROCEDURE GetRecords
> > AS
> > DECLARE
> >     @sql varchar(8000)
> >
> > WHILE (SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE
> > TABLE_NAME='MyTable') IS NOT NULL
> > BEGIN
> >     SET @sql='SELECT DISTINCT(COLUMN_NAME) FROM MyTable WHERE COLUMN_NAME
> > IS NOT NULL ORDER BY COLUMN_NAME'
> > END
> > EXEC (@sql)
> > ----------------------------------------
> >
> > But when the above is executed in QA, as expected, it throws the
> > "Subquery returned more than 1 value. This is not permitted......"
> > error.
> >
> > So how do I get the column names & then retrieve the DISTINCT records
> > from each column?
> >
> > Thanks,
> >
> > Arpan
> >
> >
Author
30 Sep 2005 12:12 AM
Arpan
Thanks, Alejandro, for your suggestion. The procedure, as such, works
fine but the only hitch is all the records are returned in one single
column, something like this (in QA):

Col1
-----------------
Rec1
Rec2
Rec3
Rec4
Rec5

Col2
----------------
Rec1
Rec3
Rec4

Col3
----------------
Rec2
Rec4
Rec5

How do I display the records in the conventional manner like this:

Col1    Col2     Col3
-----   -----    -----
Rec1    Rec1      Rec2
Rec2    Rec3      Rec4
Rec3    Rec4      Rec5
Rec4
Rec5

Thanks once again,

Regards,

Arpan
Author
29 Sep 2005 9:04 PM
Tibor Karaszi
> I am not aware of
> the no. of columns existing in that DB table. Neither am I aware of the
> column names while coding. Also more columns can get added to the table
> in the future.

Ouch. I wouldn't want to be in your shoes. The first thing to ask yourself is who designed this, and
why and if you need to live with it...

As for your code, the SELECT in the while loop is no way connected to the first SELECT. You can do
this using a cursor, though:

USE pubs
GO

CREATE PROCEDURE GetRecords
AS
SET NOCOUNT ON
DECLARE @col sysname, @sql varchar(8000)
DECLARE c CURSOR FOR
SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME='authors'
OPEN c
FETCH NEXT FROM c INTO @col
WHILE @@FETCH_STATUS = 0
BEGIN
SET @sql='SELECT DISTINCT ' + @col + ' FROM authors WHERE ' + @col + ' IS NOT NULL ORDER BY ' +
@col + ''
--PRINT @sql
EXEC (@sql)
FETCH NEXT FROM c INTO @col
END
CLOSE c
DEALLOCATE c

Show quote
"Arpan" <arpan***@hotmail.com> wrote in message
news:1128025951.296851.198910@g43g2000cwa.googlegroups.com...
> My application retrieves records from a SQL Server 7.0 DB table for
> which I am using a stored procedure but while coding, I am not aware of
> the no. of columns existing in that DB table. Neither am I aware of the
> column names while coding. Also more columns can get added to the table
> in the future.
>
> What I want to do is retrieve the DISTINCT records from each column &
> populate them in drop-down lists that will be finally displayed to the
> user. For each column, there will be 1 drop-down list which will be
> listing the DISTINCT records of that column. For e.g. if there are,
> say, 15 columns, there will be 15 drop-down lists i.e. one drop-down
> for each column. Had I known the column names while coding, the
> following queries would have sufficed:
>
> SELECT DISTINCT(Col1) FROM MyTable ORDER BY Col1
> SELECT DISTINCT(Col2) FROM MyTable ORDER BY Col2
> SELECT DISTINCT(Col3) FROM MyTable ORDER BY Col3
> ............
> ............
>
> but since the column names are not known, the above won't work in my
> case. I have to get the column names first. To do so, I am using the
> INFORMATION_SCHEMA.COLUMNS view in my stored procedure to first get the
> column names & then looping through the columns to get the DISTINCT
> records from each of the columns. This is code snippet in my stored
> procedure:
>
> ----------------------------------------
> CREATE PROCEDURE GetRecords
> AS
> DECLARE
> @sql varchar(8000)
>
> WHILE (SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE
> TABLE_NAME='MyTable') IS NOT NULL
> BEGIN
> SET @sql='SELECT DISTINCT(COLUMN_NAME) FROM MyTable WHERE COLUMN_NAME
> IS NOT NULL ORDER BY COLUMN_NAME'
> END
> EXEC (@sql)
> ----------------------------------------
>
> But when the above is executed in QA, as expected, it throws the
> "Subquery returned more than 1 value. This is not permitted......"
> error.
>
> So how do I get the column names & then retrieve the DISTINCT records
> from each column?
>
> Thanks,
>
> Arpan
>
Author
30 Sep 2005 12:37 AM
Arpan
Thanks, Tibor, for your suggestion.

Yeah....you are right.....the DB table has indeed been designed very
poorly by someone who doesn't know anything about designing DB tables &
DB programming but due to paucity of time, he wants me to adhere to
that DB only. Actually the DB table has been imported from a MS-Excel
file.

BTW, is adding columns to a DB table, dynamically or manually, after
that table has been in use for a considerable period of time a bad
practice?

Why doesn't EXEC (@sql) in your procedure generate any resultset?

Thanks once again,

Regards,

Arpan
Author
30 Sep 2005 7:59 AM
Tibor Karaszi
> Why doesn't EXEC (@sql) in your procedure generate any resultset?

Strange... when I execute the GetRecords procedure in the pubs database, from Query Analyzer, I get
a number of resultsets back...


> BTW, is adding columns to a DB table, dynamically or manually, after
> that table has been in use for a considerable period of time a bad
> practice?

Things in the organization might change, to DDL changes can be required, often with a new version of
the software. Frequent DDL changes can be, IMO, a less than perfect datamodel. Possibly not
normalized.
Show quote
"Arpan" <arpan***@hotmail.com> wrote in message
news:1128040629.262128.211750@g43g2000cwa.googlegroups.com...
> Thanks, Tibor, for your suggestion.
>
> Yeah....you are right.....the DB table has indeed been designed very
> poorly by someone who doesn't know anything about designing DB tables &
> DB programming but due to paucity of time, he wants me to adhere to
> that DB only. Actually the DB table has been imported from a MS-Excel
> file.
>
> BTW, is adding columns to a DB table, dynamically or manually, after
> that table has been in use for a considerable period of time a bad
> practice?
>
> Why doesn't EXEC (@sql) in your procedure generate any resultset?
>
> Thanks once again,
>
> Regards,
>
> Arpan
>
Author
1 Oct 2005 4:08 AM
Arpan
I am sorry Tibor.....there was a typo in the stored procedure due to
which no resultset was generated. The typo was in

FOR SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE
TABLE_NAME='MyTable' ORDER BY ORDINAL_POSITION

line. I had coded it as

FOR SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE
TABLE_NAME='MyTable ORDER BY ORDINAL_POSITION'

but stangely enough, neither the procedure generated any error while
compiling nor were any errors generated when the procedure was executed
in QA. Why so? Is it because the compiler presumed the table name to be
'MyTable ORDER BY ORDINAL_POSITION'? If so, then shouldn't the compiler
have generated the "Invalid object name" error since no such table
exists in the DB?

Another question that has been coming to my mind after going through
your code & Alejandro's code is it is said that, if I am not mistaken,
using cursors should be avoided as far as possible in DB programming.
Using dynamic SQL queries also has its drawbacks; so how does an
amateur (like me!) understand when to use cursors & when to use dynamic
SQL?

Thanks,

Regards,

Arpan
Author
1 Oct 2005 11:46 AM
Hugo Kornelis
On 30 Sep 2005 21:08:03 -0700, Arpan wrote:

Show quote
>I am sorry Tibor.....there was a typo in the stored procedure due to
>which no resultset was generated. The typo was in
>
>FOR SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE
>TABLE_NAME='MyTable' ORDER BY ORDINAL_POSITION
>
>line. I had coded it as
>
>FOR SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE
>TABLE_NAME='MyTable ORDER BY ORDINAL_POSITION'
>
>but stangely enough, neither the procedure generated any error while
>compiling nor were any errors generated when the procedure was executed
>in QA. Why so? Is it because the compiler presumed the table name to be
>'MyTable ORDER BY ORDINAL_POSITION'? If so, then shouldn't the compiler
>have generated the "Invalid object name" error since no such table
>exists in the DB?

Hi Arpan,

The compiler simply produced a plan to find all rows in the
INFORMATION_SCHEMA.COLUMNS view for a table named 'MyTable ORDER BY
ORDINAL_POSITION'. That in itself is a valid query. (And in fact - if
you really want it, you CAN have a table with that name!!)

When you execute the procedure and open the cursor, it turns out that
there are no columns in a table with that name. As a result, the first
FETCH from the cursor will result in FETCH_STATUS <> 0 and the code in
the WHILE loop will never execute.


>Another question that has been coming to my mind after going through
>your code & Alejandro's code is it is said that, if I am not mistaken,
>using cursors should be avoided as far as possible in DB programming.
>Using dynamic SQL queries also has its drawbacks; so how does an
>amateur (like me!) understand when to use cursors & when to use dynamic
>SQL?

The real answer is that you shouldn't be using cursors and dynamic sql.
You should be busy redesigning your model. Or rather - that's what you
should be doing if you inherited it. If you designed it yourself, you
should be attending a crash course on data modelling, and THEN go for
the redesign.

But we all know that sometimes you are stuck with a bad model and you
need to get some data from it NOW and can only fix the real problem
later.

Best, Hugo
--

(Remove _NO_ and _SPAM_ to get my e-mail address)

AddThis Social Bookmark Button