简体   繁体   中英

Is it possible to select only columns where at least one value is present?

I need to select all coulmns where at least one value is present. For example if this is my table:

----------------------------
name   |  keyword  |  zip
----------------------------
User1  |  test     |  ""
User2  |  test     |  ""
User3  |  ""       |  ""

Should output something like this:

-----------------
name   |  keyword  
-----------------
User1  |  test     
User2  |  test     
User3  |  ""       

The thing is that zip might not be empty and in this case the output should also include the zip column. The actual table I need this functionality for has many more columns that can potentially be empty.

I tried using SELECT * FROM myTable HAVING COUNT(*) > 0 but that did not work (empty columns were still showing).

Also tried solving it with php using loops but didn't get far that way either.

Is something like this even possible using SQL or should it be done using php for example?

SOLUTION

Here's the solution I came up with in PHP using the suggestions I got for this question.

$stack = array("keyword", "zip");
$id = $_POST["id"];
$sql = "SELECT name";
foreach($stack as $i){
    $q = "SELECT ".$i." FROM myTable WHERE ".$i." != '' AND id = '".$id."'";
    $result = mysqli_query($link, $q);
    if(mysqli_num_rows($result) > 0){
        $sql = $sql.", ".$i;
    }
}
$sql = $sql." FROM myTable WHERE id = '".$id."'";

This will output the following sql query: SELECT name, keyword FROM myTable WHERE id = 'postedId'

Notice the zip is missing from select, this is because for that particular query there were no values in zip. In the $stack array you can put whatever columns you want to check.

Also make note of how I used != '' to check for empty values but if your table has empty values as NULL make sure to use IS NOT NULL instead.

This is quite painful and not really in the spirit of SQL -- where a select statement has a fixed number of columns defined when the statement is written.

That said, you can use two levels of dynamic SQL, one to get the columns and one to use them:

-- generate the SQL to identify the columns

select @sql := group_concat(replace('select max(''[column_name]'') as col from t having count([column_name]) > 0', '[column_name]', c.column_name)
                    separator ' union all ' )
from information_schema.columns c
where table_name = 't';

-- use the SQL to get the columns
select @sql := concat('select group_concat(col separator '', '') into @cols from (', @sql, ') x');

-- run the SQL
prepare s from @sql;
execute s  ;

-- create the final query using the columns
set @sql2 = concat('select ', @cols, ' from t');

-- and execute it
prepare s2 from @sql2;
execute s2;

Note: in a real application, you would want to deallocate the prepared statements.

Here is a db<>fiddle illustrating this process.

This is not a the real answer.
Just an example of how it could be done in Oracle (I got very little experience with MySQL):

DECLARE
  has_keyword INTEGER;
  has_zip     INTEGER;
  sql         VARCHAR2(1024);
BEGIN

  -- Determine the columns having at least 1 row with a not null value
  SELECT CASE WHEN MAX(keyword) IS NULL THEN 0 ELSE 1 END,
         CASE WHEN MAX(zip)     IS NULL THEN 0 ELSE 1 END
    INTO has_keyword,
         has_zip
    FROM my_table;

  -- Compose query
  sql := 'SELECT name';
  IF (has_keyword > 0) THEN
    sql := sql || ', keyword';
  END IF;
  IF (zip > 0) THEN
    sql := sql || ', zip';
  END IF;
  sql := sql || ' FROM my_table';

  -- Execute query
  EXECUTE IMMEDIATE sql;

END;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM