1

I need to merge a table with ID and various bit flags like this

-----------------
a1 | x |   | x |
-----------------
a1 |   | x |   |
-----------------
a1 |   |   |   |
-----------------
b2 | x |   |   |
-----------------
b2 |   |   |   |
-----------------
c3 | x | x | x |

into such form

-----------------
a1 | x | x | x |
-----------------
b2 | x |   |   |
-----------------
c3 | x | x | x |

The problem is that data are join by kind of option ID each option has an unique ID which is joined with a1, b2. When I try to SELECT it by using DISTINCT I receive results from table number 1. I can make it by subqueries in SELECT but it is really weak solution due to performance reasons.

Do you have any idea how select and combine all these flags into single row?

1
  • Simply GROUP BY. Commented Feb 20, 2019 at 13:15

4 Answers 4

3

use aggregation

select col1 ,max(col2),max(col3),max(col4)
form table_name group by col1
Sign up to request clarification or add additional context in comments.

Comments

1

For the given result set it is eligible to use MIN and GROUP BY:

SELECT 
tbl.Col
, MIN(tbl.Col1) Col1
, MIN(tbl.Col2) Col2 
, MIN(tbl.Col3) Col3 
FROM @table tbl
GROUP BY tbl.Col

However, if you have empty rows, then use MAX(). Otherwise MIN() returns empty rows:

SELECT 
tbl.Col
, MAX(tbl.Col1) Col1
, MAX(tbl.Col2) Col2 
, MAX(tbl.Col3) Col3 
FROM @table tbl
GROUP BY tbl.Col

For example:

DECLARE @table TABLE
(
    Col  VARCHAR(50),
    Col1 VARCHAR(50), 
    Col2 VARCHAR(50), 
    Col3 VARCHAR(50) 
)

INSERT INTO @table
(
    Col,
    Col1,
    Col2,
    Col3
)
VALUES
(   'a1', -- Col - varchar(50)
    'x', -- Col1 - varchar(50)
    Null, -- Col2 - varchar(50)
    'x'  -- Col3 - varchar(50)
    )
, ('a1', NULL, 'x', null)
, ('a1', NULL, 'x', null)
, ('b2', 'x', null, null)
, ('b2', null, null, null)
, ('c3', 'x', 'x', 'x')

SELECT 
tbl.Col
, MIN(tbl.Col1) Col1
, MIN(tbl.Col2) Col2 
, MIN(tbl.Col3) Col3 
FROM @table tbl
GROUP BY tbl.Col

OUTPUT:

Col Col1    Col2    Col3
a1   x        x       x
b2   x       NULL   NULL
c3   x        x       x

3 Comments

@Larnu Yeah, for this result set it works correctly.
I don't understand. MIN skips nulls and MAX doesn't? That's new to me.
MIN and MAX both ignore nulls So both return the non-null value. Only if two or more non-null values per ID exist, would MIN return the lesser value and MAX the greater one. This has nothing to do with "empty rows".
1

You want aggregation :

select col1, max(col2), max(col2), max(col3)
from table t
group by col1;

This assuming blank value as null.

Comments

1

The general solution for such a situation is to simply aggregate and either use MIN or MAX on the columns.

SQL Server's data type BIT, however, is quirky. It's a little like a BOOLEAN, but not a real boolean. It is a little like a very limited numeric data type, but it isn't really a numeric type either. And there simply exist no aggregation functions for this data type. In standard SQL you'd have ANY and EVERY for the BOOLEAN type. In PostgreSQL you have BIT_OR and BIT_AND for BIT and BOOL_OR and BOOL_AND for BOOLEAN. SQL Server has nothing.

So convert your columns to a numeric type before using MIN (which would be a bitwise AND) or MAX (which would be a bitwise OR) on it. E.g.

select
  id,
  max(bit1 + 0) as bit1agg,
  max(bit2 + 0) as bit2agg,
  max(bit3 + 0) as bit3agg
from mytable
group by id
order by id;

You can also use CAST or CONVERT instead of course.

1 Comment

Yep I casted Bit as integer and it works fine :) Thank you for reply

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.