-1

I was wondering if it's ok to use sql HAVING to find certain rows in a table.

Example:

I have a table with three columns -> ID (int, primary key), type and size (varchar)

One row looks like this:

ID     type          size 
1      15; 16; 17    4; 8

And to select a row that has a type 15 i use the following query

SELECT * FROM tableName WHERE type HAVING "15"

Is it ok to do it this way, or is there a better way?

Thank you in advance!

gogo_rulez
  • 389
  • 2
  • 10
  • 24

2 Answers2

2

Your syntax would not work in most databases. It would happen to work in MySQL, because MySQL allows having clauses for non-aggregation queries.

Even in MySQL, the clause would do nothing, because "15" is simply a number. In a boolean context, non-zero numbers are interpreted as "true" and zeros as "false". What you want to use is where:

select *
from table
where type = 15;

Alas, this will not work for you because you have a messed up data structure. You should not be storing lists in strings. You should be storing them in junction tables (you can Google the term to learn more about it). So, the best way is to store the data correctly.

If you have to use this data structure (say, you are on a deserted island and they won't send you food unless you write queries on such a database), then you can use like or find_in_set(). The first is easier in this case:

where concat('; ', type, '; ') like '%; 15; %'
Gordon Linoff
  • 1,242,037
  • 58
  • 646
  • 786
0

No, you will have to do a LIKE

CREATE TABLE #test(
ID int, 
[type] varchar(255), 
[size] varchar(255)
);

insert into #test VALUES(1, '15; 16; 17;', '4; 8;')

select * from #test where [type] like '%15%'

Returns

ID   type       Size
1   15; 16; 17; 4; 8;

Or you could combine an IN statement with a Split function:

Usage

declare @val varchar(255);
set @val = 15

select * from #test t where @val in (select Value from [dbo].udf_Split(t.[type], ';') as i)

Function

CREATE Function [dbo].[udf_Split]
(   
    @DelimitedList nvarchar(max)
    , @Delimiter nvarchar(2)
)
RETURNS TABLE 
AS
RETURN 
    (
    With CorrectedList As
        (
        Select Case When Left(@DelimitedList, Len(@Delimiter)) <> @Delimiter Then @Delimiter Else '' End
            + @DelimitedList
            + Case When Right(@DelimitedList, Len(@Delimiter)) <> @Delimiter Then @Delimiter Else '' End
            As List
            , Len(@Delimiter) As DelimiterLen
        )
        , Numbers As 
        (
        Select TOP( Coalesce(DataLength(@DelimitedList)/2,0) ) Row_Number() Over ( Order By c1.object_id ) As Value
        From sys.columns As c1
            Cross Join sys.columns As c2
        )
    Select CharIndex(@Delimiter, CL.list, N.Value) + CL.DelimiterLen As Position
        , Substring (
                    CL.List
                    , CharIndex(@Delimiter, CL.list, N.Value) + CL.DelimiterLen     
                    , CharIndex(@Delimiter, CL.list, N.Value + 1)                           
                        - ( CharIndex(@Delimiter, CL.list, N.Value) + CL.DelimiterLen ) 
                    ) As Value
    From CorrectedList As CL
        Cross Join Numbers As N
    Where N.Value <= DataLength(CL.List) / 2
        And Substring(CL.List, N.Value, CL.DelimiterLen) = @Delimiter
    )

Returns

ID   type       Size
1   15; 16; 17; 4; 8;
ZeroBased_IX
  • 2,667
  • 2
  • 25
  • 46