-1

I did some searching, and most returned the table names or was a bit over-kill for my needs (replacing data..if higher/lower..etc)

I have an existing table I need to work with:

id | booth_100 | booth_101 | booth_102 | booth_103 | booth_105 | booth_121  | booth_200 | booth_201...etc.
  • My current understanding (didn't create this odd table) is there will only be '1' row
  • Only '1' of the 'booth_xxx' columns will have a value in it.

How can I build a pipe (|) delimited string using ONLY the 'booth_' column names IF it doesn't have a value in it?

id | booth_100 | booth_101 | booth_102 | booth_103 | booth_105 | booth_121  | booth_200 | booth_201

1  |    1      |    0      |     0     |      0    |     0          1       |     1     |     0

I would like to figure out how to get a returned results of:

booth_100|booth_121|booth200

as my returned query/string.

Is there an easy way to do this? (or some long way that needs to list out every column name in the query itself?.. which I'd still like help with if that's the only route)

SQL Fiddle for table example:

Another example/attempt: (but this one REQUIRES the columns to be bit not int?)..if I use int for col type. the query part fails? (not sure what I am doing wrong though?)

http://sqlfiddle.com/#!18/f80c8/1/0

aynber
  • 22,380
  • 8
  • 50
  • 63
whispers
  • 962
  • 1
  • 22
  • 48

1 Answers1

1

Your title says "SQL Server" but your sqlfiddle uses MySQL so I'm hoping it is SQL Server you want. The non-normalized table you are using really should be "flipped" or "unpivotted" which you can do using a cross apply as shown below. Once you have the data in a more normalized shape, then you can use STRING_AGG() provided you have SQL Server 2017 or later.

SQL Fiddle

SQL Server 2017 Schema Setup:

create table exhibitors_booth(
  id int primary key,
  booth_100 int,
  booth_101 int,
  booth_102 int,
  booth_103 int,
  booth_104 int,
  booth_200 int,
  booth_201 int,
  booth_202 int,
  booth_203 int
);

insert into exhibitors_booth values
('1', 1, 0, 1, 1, 0, 0, 0, 0, 1);

SELECT
    CrossApplied.*
into exhibitors
FROM exhibitors_booth
CROSS APPLY (
    VALUES 
                (1, 'booth_100', booth_100)
              , (2, 'booth_101', booth_101)
              , (3, 'booth_102', booth_102)
              , (4, 'booth_103', booth_103)
              , (5, 'booth_104', booth_104)
              , (6, 'booth_201', booth_200)
              , (7, 'booth_202', booth_201)
              , (8, 'booth_203', booth_202)
              , (9, 'booth_204', booth_203)
            ) AS CrossApplied(SeqNo, Booth, YesNo)
;

Query 1:

select * from exhibitors_booth

Results:

| id | booth_100 | booth_101 | booth_102 | booth_103 | booth_104 | booth_200 | booth_201 | booth_202 | booth_203 |
|----|-----------|-----------|-----------|-----------|-----------|-----------|-----------|-----------|-----------|
|  1 |         1 |         0 |         1 |         1 |         0 |         0 |         0 |         0 |         1 |

Query 2:

select * from exhibitors

Results:

| SeqNo |     Booth | YesNo |
|-------|-----------|-------|
|     1 | booth_100 |     1 |
|     2 | booth_101 |     0 |
|     3 | booth_102 |     1 |
|     4 | booth_103 |     1 |
|     5 | booth_104 |     0 |
|     6 | booth_201 |     0 |
|     7 | booth_202 |     0 |
|     8 | booth_203 |     0 |
|     9 | booth_204 |     1 |

Query 3:

select
string_agg(booth,',') as booths
from exhibitors

Results:

|                                                                                    booths |
|-------------------------------------------------------------------------------------------|
| booth_100,booth_101,booth_102,booth_103,booth_104,booth_201,booth_202,booth_203,booth_204 |

I am assuming this is the wanted result. If that's not true please modify your question to include the result you are seeking.

If you do not want to use the "flipped" table just place that code into a cte (or derived table), like this:

with cte as (
    SELECT
        CrossApplied.*
    FROM exhibitors_booth
    CROSS APPLY (
        VALUES 
                    (1, 'booth_100', booth_100)
                  , (2, 'booth_101', booth_101)
                  , (3, 'booth_102', booth_102)
                  , (4, 'booth_103', booth_103)
                  , (5, 'booth_104', booth_104)
                  , (6, 'booth_201', booth_200)
                  , (7, 'booth_202', booth_201)
                  , (8, 'booth_203', booth_202)
                  , (9, 'booth_204', booth_203)
                ) AS CrossApplied(SeqNo, Booth, YesNo)
      )
select
string_agg(booth,',') as booths
from cte
;
Paul Maxwell
  • 33,002
  • 3
  • 32
  • 51
  • Thank you for the reply. I have updated the SQL Fiddle example to be MS SQL SERVER 2017 now... (but my attempt couldnt use int..only bit for the query?). I did provide an example of how it should look (which matches your results).. What I dont get or really want to do it.. the extra table stuff? (dont reallt have access, can only use that existing table with that existing structure) My latest example show somewhat of a solution.. but table cols are bit.. can you help convert? so table can be int and query still works? thanks – whispers Oct 14 '21 at 04:28
  • You can use my sqlfiddle which has already removed the `(1)` from the `int` when building your table. You do not "have to" use a different table, just use the code that produced the table as a cte or derived table, then use the string_agg against that. However, at some point in your database life you may come to understand that tables such as exhibitors_booth are incorrectly designed, eventually it will drive you nuts and you will want to know how to flip it then. There's an new query to demonstrate this. – Paul Maxwell Oct 14 '21 at 05:23
  • It already drives me nuts! LOL I'm not great with SQL/queries.. but even I know this layout is not easy to work with/wrong. Thank you for the updated example. However it selects ALL column names.. not just ones that are blank (or even opposite -do- have a value in the column) -- http://sqlfiddle.com/#!18/bcb4c0/2/0 – whispers Oct 14 '21 at 13:15
  • Your comment about removing the (1) after the int declaration seems to have worked my example now as well (thanks) --- http://sqlfiddle.com/#!18/c1e41d/2/0 – whispers Oct 14 '21 at 13:18
  • It appears you have your answer. Including a where clause allows you to filter for just those with 1 in the YesNo column (or you could filter for 0). Also not sure why you used `for xml path` perhaps look at this http://sqlfiddle.com/#!18/c1e41d/5 which display using the pipe character as a parameter to string_agg. – Paul Maxwell Oct 15 '21 at 01:48