私はTable
10個のフィールドを持っています。それぞれのfield
orには値column
が含まれInteger
ます。
Null
これで、または0
結果セットに含まれるフィールドのみを返す必要があります。
あなたが何を求めているのかは明らかではありません。
結果セットがどのように表示されるかについて少し詳しく説明していただけますか? これは、WHERE 句で適切な述語を指定することにより、非常に簡単に行うことができます。
SELECT col0, col1, col2, col3, col4, col5, col6, col7, col8, col9
FROM mytable
WHERE IFNULL(col0,0) = 0
OR IFNULL(col1,0) = 0
OR IFNULL(col2,0) = 0
OR IFNULL(col3,0) = 0
OR IFNULL(col4,0) = 0
OR IFNULL(col5,0) = 0
OR IFNULL(col6,0) = 0
OR IFNULL(col7,0) = 0
OR IFNULL(col8,0) = 0
OR IFNULL(col9,0) = 0
これにより、指定された列の少なくとも 1 つにゼロまたは NULL があるすべての行が返されます。
しかし、あなたの質問は少し違うことについて尋ねているようです。条件に基づいて特定の列のみを返すことについて質問しているようです。SELECT
結果セットで返される列は、キーワードに続く式のリストによって決まります。列に含まれる値に基づいて、SELECT リストの式を動的に変更することはできません。
その列に NULL またはゼロを含む行が少なくとも 1 つある列の名前を返すには、次のようなクエリを記述できます (これは 5 列に制限されており、10 列以上に簡単に拡張できます)。
SELECT 'col0' AS col_name FROM mytable WHERE IFNULL(col0,0) = 0
UNION SELECT 'col1' FROM mytable WHERE IFNULL(col1,0) = 0
UNION SELECT 'col2' FROM mytable WHERE IFNULL(col2,0) = 0
UNION SELECT 'col3' FROM mytable WHERE IFNULL(col3,0) = 0
UNION SELECT 'col4' FROM mytable WHERE IFNULL(col4,0) = 0
(そのクエリは、テーブル全体でいくつかの深刻なスキャンを実行します。インデックスが使用可能な場合は、述語を書き直して、インデックス範囲スキャンを可能にすることができます。)
column_names を 1 行で表示する方法を次に示します。(いずれかの列の NULL は、その列にゼロまたは NULL が含まれていないことを意味します。)
SELECT (SELECT 'col0' FROM mytable WHERE IFNULL(col0,0)=0 LIMIT 1) AS col0
, (SELECT 'col1' FROM mytable WHERE IFNULL(col1,0)=0 LIMIT 1) AS col1
, (SELECT 'col2' FROM mytable WHERE IFNULL(col2,0)=0 LIMIT 1) AS col2
, (SELECT 'col3' FROM mytable WHERE IFNULL(col3,0)=0 LIMIT 1) AS col3
, (SELECT 'col4' FROM mytable WHERE IFNULL(col4,0)=0 LIMIT 1) AS col4
ただし、テーブルを 1 回スキャンする方がはるかに高速です。
SELECT IF(c0>0,'col0',NULL)
, IF(c1>0,'col1',NULL)
, IF(c2>0,'col2',NULL)
, IF(c3>0,'col3',NULL)
, IF(c4>0,'col4',NULL)
FROM ( SELECT SUM(IF(IFNULL(col0,0)=0,1,0)) AS c0
, SUM(IF(IFNULL(col1,0)=0,1,0)) AS c1
, SUM(IF(IFNULL(col2,0)=0,1,0)) AS c2
, SUM(IF(IFNULL(col3,0)=0,1,0)) AS c3
, SUM(IF(IFNULL(col3,0)=0,1,0)) AS c4
FROM mytable
)
使用するwhere column_name is null or column_name = 0
最近、別の言語で同様のメソッドを作成する必要がありました。ロジックは、レコードを処理する前に、レコード内のすべての「列」が「true」であることを確認することでした。
私がそれを回避した方法は、次のロジックでした。
# loop through the records
for ($i=0; $i<count($records); $i++) {
# in each record, if any column is 0 or null we will disgard it
# this boolean will tell us if we can keep the record or not
# default value is 'true', this gives it a chance to survive
$keepit = true;
# loop through each column
for ($j=0; $j<count($records[$i]); $j++) {
# add your boolean condition (true=go ahead, false=cant go ahead)
$goahead = (!is_null($records[$i][$j]) && $records[$i][$j] != 0);
# convert the boolean to a 0 or 1,
# find the minimum number in a record
# (so if any field in a record is false i.e. 0 or null, dont use the record)
$keepit = min(+$goahead, +$keepit);
}#end of col loop
if ($keepit) {
# keep the record
array_push($anotherArray, $records[$i]);
}
}
私はあなたのためにこれをPHPで書きました。おそらく MySQL でも実行可能ですが、すべてのレコードを取得して PHP で処理し、MySQL に送り返すことをお勧めします。
将来的には、無効なレコードが許可されないように、または最初から保存されないように、データベース テーブルを設計する必要があります。
NULL または 0 を含む列、または NULL または 0 の列を含む行、またはすべての列が NULLまたは 0 である行が必要ですか?
しかし、適切に設計されたテーブルに 10 個の同等の列があるとは思えないので、データ モデルを再設計する必要があるかもしれません。別のテーブルで列の行を作成し、2 つのテーブルを結合します。
次のようなものがあるかもしれません:
CREATE TABLE a(a_id int primary key, b0 int, b1 int, b2 int, ..., b9 int );
しかし、あなたはこれが欲しい:
CREATE TABLE a( a_id int primary key );
CREATE TABLE b( b_id int primary key );
INSERT INTO b (b_id) values (0), (1), ..., (9);
CREATE TABLE ab (
a_id int, b_id int,
v int not null, -- this would be the value of b0, b1, ...
foreign key (a_id) references a(a_id),
foreign key (b_id) references b(b_id),
primary key(a_id, b_id)
);
そして、次のように書くことができます:
SELECT * FROM a, b -- cross join to get all possible combinations
WHERE (a_id, b_id) NOT IN (
-- then remove the ones that have a value
SELECT a_id, b_id FROM a JOIN ab ON a.id = ab.a_id JOIN b ON ab.a_id
WHERE ab.v <> 0);
最後の行は、実行する前に 0 の行をすべて削除する場合は不要です。
DELETE FROM ab WHERE v = 0;