Sql query where condition and or - mysql

I have the following data in my table:
id: 1, name: TOM, visible: 1, field_1: EMPTY, field_2: EMPTY, field_3: EMPTY.
SELECT id, name FROM table
WHERE name <> 'TOM' AND visible = 1
AND field_1 <> '' OR field_2 <> '' OR field_3 <> ''
I want to select only the rows where name is different than 'name1' and at least one of the fields is not empty.
I expected no results for this query but i get: id, TOM like the where name condition is overwritten.

Your problem is precedence: bracket the ORs:
SELECT id, name
FROM table
WHERE name <> 'TOM'
AND visible = 1
AND (field_1 <> '' OR field_2 <> '' OR field_3 <> '')

I suspect, that one of the field is really != '', making the condition valid for "Tom" record. You must group OR conditions, using brackets:
SELECT id, name FROM table
WHERE name <> 'TOM' AND visible = 1
AND (field_1 <> '' OR field_2 <> '' OR field_3 <> '')

The and operator has a higher precedence than or (see the documentation for extra details), so if we take your query:
SELECT id, name FROM table
WHERE name <> 'TOM' AND visible = 1
AND field_1 <> '' OR field_2 <> '' OR field_3 <> ''
And add clarifying parentheses, we'll get:
SELECT id, name FROM table
WHERE (name <> 'TOM' AND visible = 1 AND field_1 <> '')
OR field_2 <> ''
OR field_3 <> ''
Which is not what you wanted. You can solve this by explicitly adding parentheses:
SELECT id, name
FROM table
WHERE name <> 'TOM' AND
visible = 1 AND
(field_1 <> '' OR field_2 <> '' OR field_3 <> '')

You should add ()
SELECT id, name
FROM table
WHERE name <> 'TOM'
AND visible = 1
AND (field_1 <> ''OR field_2 <> '' OR field_3 <> '')

Please enclose empty fields comparison in one paranthesis block as show in bold
SELECT id, name FROM table
WHERE name <> 'TOM' AND visible = 1
AND ( field_1 <> '' OR field_2 <> '' OR field_3 <> '' )

You have to insert brackets
Are the empty fields really empty? Maybe the '' doesn't bring the right results

Related

Sql add condition IF

I have sql like :
SELECT * FROM leads_notes WHERE content <> '' AND lead_id <> ''
I need add rule if type <> close_task then write user_change_task_status IS NULL
My result sql is:
SELECT * FROM leads_notes WHERE content <> '' AND lead_id <> '' IF(task_type <> 'close_task', 'AND user_change_task_status IS NULL',)
But i get many errors.
Cant understand how can i solve this. Please help, thanks!
Don't use if. Boolean logic is sufficient:
WHERE content <> '' AND
lead_id <> '' AND
( type = 'close_task' or user_change_task is null)
Or:
WHERE content <> '' AND
lead_id <> '' AND
NOT ( type = 'close_task' and user_change_task is not null )

SQL Convert a char to boolean

I have in my table one row with a char value. When the value is NULL then a false should be outputted. If the value is not NULL then a true should be outputted.
So when I try to set user_group.tUser to 0 or 1 then I'm getting this error:
Invalid column name 'false'.
Invalid column name 'true'.
SELECT COALESCE((SELECT name
FROM v_company
WHERE companyId = userView.companyId), ' ') AS company,
userView.value AS companyUser,
userView.display AS displayedUser,
CASE
WHEN user_group.tUser IS NULL THEN 0
ELSE 1
END AS userIsMemberOfGroup
FROM v_user userView
LEFT OUTER JOIN cr_user_group user_group
ON ( user_group.group = 'Administrators'
AND user_group.tUser = userView.value )
ORDER BY company ASC,
displayedUser ASC
I think this is the logic you want:
SELECT COALESCE(v.name, ' ') as company,
u.value as companyUser, u.display as displayedUser,
(EXISTS (SELECT 1
FROM cr_user_group ug
WHERE ug.group = 'Administrators' AND
ug.tUser = uv.value
)
) as userIsMemberOfGroup
FROM v_user u LEFT JOIN
v_company c
ON c.companyId = v.companyId
ORDER BY company ASC, displayedUser ASC ;
In general, MySQL is very flexible about going between booleans and numbers, with 0 for false and 1 for true.
You can use MySQL IF function to return 'false' when name IS NULL, else 'true':
SELECT IF(name IS NULL, 'false', 'true')
FROM table;
A simple CASE expression would work here:
SELECT
name,
CASE WHEN name IS NOT NULL THEN true ELSE false END AS name_out
FROM yourTable;
We could also shorten the above a bit using IF:
IF(name IS NOT NULL, true, false)
SELECT
CASE
WHEN name IS NULL THEN 'false'
ELSE 'true'
END
FROM
table1;

SQL Server Row totals in pivot query

I am trying to make a row in the end of the result set that shows the totals.
My query is this:
SELECT
[ ] = ISNULL(CAST(GEN_idPaciente AS VARCHAR)+'-'+nombrePaciente, 'TOTAL'),
[2016-11-01] = MAX([2016-11-01]),
[2016-11-02] = MAX([2016-11-02]),
[2016-11-03] = MAX([2016-11-03]),
[2016-11-04] = MAX([2016-11-04]),
TOTAL = COUNT([2016-11-01]) + COUNT([2016-11-02]) + COUNT([2016-11-03]) + COUNT([2016-11-04])
FROM
(
SELECT GEN_Paciente.GEN_idPaciente,COALESCE(GEN_ape_paternoPaciente, '')+' '+COALESCE(GEN_ape_maternoPaciente, '')+' '+COALESCE(GEN_nombrePaciente, '') AS nombrePaciente,HOS_fechaCategorizacion,HOS_nivel_riesgoCategorizacion+CAST(HOS_nivel_dependenciaCategorizacion AS VARCHAR) as riesgoDependencia
FROM HOS_Categorizacion
INNER JOIN HOS_Hospitalizacion
ON HOS_Hospitalizacion.HOS_idHospitalizacion = HOS_Categorizacion.HOS_idHospitalizacion
INNER JOIN GEN_Paciente
ON GEN_Paciente.GEN_idPaciente = HOS_Hospitalizacion.GEN_idPaciente
WHERE HOS_nivel_riesgoCategorizacion IS NOT NULL
) src
PIVOT
(
MAX(riesgoDependencia)
for HOS_fechaCategorizacion in ([2016-11-01],[2016-11-02],[2016-11-03],[2016-11-04])
) p
GROUP BY
ROLLUP(CAST(GEN_idPaciente AS VARCHAR)+'-'+nombrePaciente)
This gives me this result:
But as you can see the totals for the rows are right but the totals for the columns are wrong because I am using MAX instead of COUNT, but I only need COUNT in the TOTAL row, the others have to be MAX, so I wrote this query:
SELECT
[ ] = ISNULL(CAST(GEN_idPaciente AS VARCHAR)+'-'+nombrePaciente, 'TOTAL'),
[2016-11-01] = CASE WHEN CAST(GEN_idPaciente AS VARCHAR)+'-'+nombrePaciente IS NOT NULL THEN MAX([2016-11-01]) ELSE COUNT([2016-11-01]) END,
[2016-11-02] = CASE WHEN CAST(GEN_idPaciente AS VARCHAR)+'-'+nombrePaciente IS NOT NULL THEN MAX([2016-11-02]) ELSE COUNT([2016-11-02]) END,
[2016-11-03] = CASE WHEN CAST(GEN_idPaciente AS VARCHAR)+'-'+nombrePaciente IS NOT NULL THEN MAX([2016-11-03]) ELSE COUNT([2016-11-03]) END,
[2016-11-04] = CASE WHEN CAST(GEN_idPaciente AS VARCHAR)+'-'+nombrePaciente IS NOT NULL THEN MAX([2016-11-04]) ELSE COUNT([2016-11-04]) END,
TOTAL = COUNT([2016-11-01]) + COUNT([2016-11-02]) + COUNT([2016-11-03]) + COUNT([2016-11-04])
FROM
(
SELECT GEN_Paciente.GEN_idPaciente,COALESCE(GEN_ape_paternoPaciente, '')+' '+COALESCE(GEN_ape_maternoPaciente, '')+' '+COALESCE(GEN_nombrePaciente, '') AS nombrePaciente,HOS_fechaCategorizacion,HOS_nivel_riesgoCategorizacion+CAST(HOS_nivel_dependenciaCategorizacion AS VARCHAR) as riesgoDependencia
FROM HOS_Categorizacion
INNER JOIN HOS_Hospitalizacion
ON HOS_Hospitalizacion.HOS_idHospitalizacion = HOS_Categorizacion.HOS_idHospitalizacion
INNER JOIN GEN_Paciente
ON GEN_Paciente.GEN_idPaciente = HOS_Hospitalizacion.GEN_idPaciente
WHERE HOS_nivel_riesgoCategorizacion IS NOT NULL
) src
PIVOT
(
MAX(riesgoDependencia)
for HOS_fechaCategorizacion in ([2016-11-01],[2016-11-02],[2016-11-03],[2016-11-04])
) p
GROUP BY
ROLLUP(CAST(GEN_idPaciente AS VARCHAR)+'-'+nombrePaciente)
But that is not working
Thanks for your help!!
If I understand this correctly you want to count all columns which are not null. In this case you should just look at the condition IS NULL and not at the actual value at all. Try this:
DECLARE #tbl TABLE(ID INT IDENTITY, val1 VARCHAR(100),val2 VARCHAR(100),val3 VARCHAR(100));
INSERT INTO #tbl VALUES
('row1_val1','row1_val2',NULL)
,('row2_val1','row2_val2','row2_val3')
,(NULL,'row2_val2',NULL)
,(NULL,NULL,'row2_val3')
,(NULL,NULL,NULL);
SELECT *
,CASE WHEN val1 IS NULL THEN 0 ELSE 1 END
+CASE WHEN val2 IS NULL THEN 0 ELSE 1 END
+CASE WHEN val3 IS NULL THEN 0 ELSE 1 END AS CountOfValNotNull
FROM #tbl
UPDATE: Add a final Totals Row
You'd need ugly fiddling with a CTE, an additional sort column, UNION ALL to add another row and a sub_select.
Use the outer-most ORDER BY to get the artificial Totals-Row to the end
hint: Use the #tbl variable from above!
WITH SortedRows AS
(
SELECT ROW_NUMBER() OVER(ORDER BY ID) AS SortColumn
,*
,CASE WHEN val1 IS NULL THEN 0 ELSE 1 END
+CASE WHEN val2 IS NULL THEN 0 ELSE 1 END
+CASE WHEN val3 IS NULL THEN 0 ELSE 1 END AS CountOfValNotNull
FROM #tbl
)
SELECT tbl1.*
FROM
(
SELECT * FROM SortedRows
UNION ALL
SELECT 999999,0,'','','',(SELECT SUM(CountOfValNotNull) FROM SortedRows)
) AS tbl1
ORDER BY tbl1.SortColumn

MySQL - Rows to Columns and keeps NULL

We have the following table (TEST2) in the MySQL database (MySQL 5.6):
TEAM_ID,MEMBER_ID,TYPE,SCORE
1,2,A,150
1,3,B,200
1,1,B,50
1,1,A,100
1,2,B,NULL
We try to transform/pivot the above table based on the TYPE column:
If the TYPE column has value == A, move the value in the SCORE column into a new column called A_SCORE. If the value in the SCORE column is NULL, it should show NULL in the new A_SCORE column.
If the TYPE column has value == B, move the value in the SCORE column into a new column called B_SCORE. If the value in the SCORE column is NULL, it should show NULL in the new B_SCORE column.
The following table is the one we are looking for (the wanted table):
TEAM_ID,MEMBER_ID,A_SCORE,B_SCORE,A_SCORE_MINUS_B_SCORE
1,1,100,50,50
1,2,150,NULL,NULL
1,3,0,200,-200
We tried the following query
SELECT TEAM_ID,MEMBER_ID,A_SCORE,B_SCORE,SUM(A_SCORE-B_SCORE) AS ACTUAL_MINUS_B_SCORE FROM
(SELECT TEAM_ID,MEMBER_ID,
CASE
WHEN SCORE IS NULL
THEN NULL
ELSE SUM(if(TYPE = 'A', SCORE,0) )
END A_SCORE,
CASE
WHEN SCORE IS NULL
THEN NULL
ELSE SUM(if(TYPE = 'B', SCORE,0) )
END B_SCORE
FROM TEST2
GROUP BY TEAM_ID,MEMBER_ID,SCORE) AS A
GROUP BY TEAM_ID,MEMBER_ID,A_SCORE,B_SCORE);
It returns something we don’t want:
TEAM_ID,MEMBER_ID,A_SCORE,B_SCORE,A_SCORE_MINUS_B_SCORE
1,1,0,50,-50
1,1,100,0,100
1,2,0,0,0
1,2,150,0,150
1,3,0,200,-200
If we tried the following, it generates a table close to what we want, but it doesn’t return any NULL value.
SELECT TEAM_ID,MEMBER_ID,A_SCORE,B_SCORE,SUM(A_SCORE-B_SCORE) AS A_SCORE _MINUS_B_SCORE FROM
(SELECT TEAM_ID,MEMBER_ID,
SUM(if(TYPE = 'A', SCORE,0) ) AS A_SCORE,
SUM(if(TYPE = 'B', SCORE,0) )AS B_SCORE
FROM TEST2
GROUP BY TEAM_ID,MEMBER_ID) AS A
GROUP BY TEAM_ID,MEMBER_ID,A_SCORE,B_SCORE;
The result of the above query:
TEAM_ID,MEMBER_ID,A_SCORE,B_SCORE,A_SCORE_MINUS_B_SCORE
1,1,100,50,50
1,2,150,0,0
1,3,0,200,-200
Could any guru enlighten how to generate the wanted table in this case using MySQL? The SQL fiddle is here for your convenience.
http://sqlfiddle.com/#!9/cfe7a1/1
Thanks!
Try this;)
SELECT TEAM_ID, MEMBER_ID, A_SCORE, B_SCORE, A_SCORE - B_SCORE AS A_SCORE_MINUS_B_SCORE
FROM (
SELECT
TEAM_ID, MEMBER_ID,
CASE
WHEN A_SCORE IS NULL AND NOT EXISTS (
SELECT 1 FROM TEST2
WHERE TEAM_ID = T1.TEAM_ID
AND MEMBER_ID = T1.MEMBER_ID
AND TYPE = 'A'
) THEN 0 ELSE A_SCORE END AS A_SCORE,
CASE
WHEN B_SCORE IS NULL AND NOT EXISTS (
SELECT 1 FROM TEST2
WHERE TEAM_ID = T1.TEAM_ID
AND MEMBER_ID = T1.MEMBER_ID
AND TYPE = 'A'
) THEN 0 ELSE B_SCORE END AS B_SCORE
FROM (
SELECT
TEAM_ID, MEMBER_ID,
MAX(CASE WHEN TYPE = 'A' THEN SCORE END) AS A_SCORE,
MAX(CASE WHEN TYPE = 'B' THEN SCORE END) AS B_SCORE
FROM TEST2
GROUP BY TEAM_ID, MEMBER_ID
) T1
)T
SQLFiddle demo here
I don't quite understand the calculation criteria, but something like this should work...
SELECT team_id
, member_id
, COALESCE(MAX(CASE WHEN type = 'A' THEN score END),0) a_score
, COALESCE(MAX(CASE WHEN type = 'B' THEN score END),0) b_score
, COALESCE(MAX(CASE WHEN type = 'A' THEN score END),0)
- COALESCE(MAX(CASE WHEN type = 'B' THEN score END),0) diff
FROM test2
GROUP
BY team_id
, member_id;

MySql, Postgres, Oracle and SQLServer ignoring IS NOT NULL filter

While I was preparing an answer to one of our fellows here on SO I've encounter an odd situation, at least to me. The original question is here: Pivot Table Omitting Rows that Have Null values
I've modified the query to use max instead of group_concat in order to show the "problem" in all databases.
SELECT
id,
max(case when colID = 1 then value else '' end) AS fn,
max(case when colID = 2 then value else '' end) AS ln,
max(case when colID = 3 then value else '' end) AS jt
FROM tbl
GROUP BY id
The result of this query is this:
ID FN LN JT
1 Sampo Kallinen Office Manager
2 Jakko Salovaara Vice President
3 (null) Foo No First Name
The user asks to filter the row with id 3 because the field value is null.
When it seems pretty obvious that only it needs to do was to add a WHERE value IS NOT NULL constraint on that query to achieve what the user expect. It won't work.
So I start to test it on the other databases to see what happens (Queries with the WHERE CLAUSE)
SELECT
id,
max(case when colID = 1 then value else '' end) AS fn,
max(case when colID = 2 then value else '' end) AS ln,
max(case when colID = 3 then value else '' end) AS jt
FROM tbl
WHERE value is not null
GROUP BY id
Mysql: http://sqlfiddle.com/#!2/78395/1
Postgres: http://sqlfiddle.com/#!15/78395/1
SQLServer: http://sqlfiddle.com/#!6/78395/1
Oracle: http://sqlfiddle.com/#!4/78395/1
For my surprise the result was the same, none worked.
Then I tried a different version of the same query:
SELECT * FROM (
SELECT
id,
max(case when colID = 1 then value else '' end) AS fn,
max(case when colID = 2 then value else '' end) AS ln,
max(case when colID = 3 then value else '' end) AS jt
FROM tbl
GROUP BY id
) T
WHERE fn IS NOT NULL
AND ln IS NOT NULL
AND jt IS NOT NULL
Oracle: http://sqlfiddle.com/#!4/78395/2 WORKED
MySql: http://sqlfiddle.com/#!2/78395/2
Postgres: http://sqlfiddle.com/#!15/78395/2
SQLServer: http://sqlfiddle.com/#!6/78395/2
The only way I could make it work on all databases was with this query:
SELECT
id,
max(case when colID = 1 then value else '' end) AS fn,
max(case when colID = 2 then value else '' end) AS ln,
max(case when colID = 3 then value else '' end) AS jt
FROM tbl
WHERE NOT EXISTS (SELECT * FROM tbl b WHERE tbl.id=b.id AND value IS NULL)
GROUP BY id
So I ask:
What is happening here that except for that specific case on Oracle all other DBs seem to ignore the IS NOT NULL filter?
To omit the row from the result if any of the source rows for the same id has value IS NULL, a solution in Postgres would be to use the aggregate function every() or (synonym for historical reasons) bool_and() in the HAVING clause:
SELECT id
, max(case when colID = 1 then value else '' end) AS fn
, max(case when colID = 2 then value else '' end) AS ln
, max(case when colID = 3 then value else '' end) AS jt
FROM tbl
GROUP BY id
HAVING every(value IS NOT NULL);
SQL Fiddle.
Explain
Your attempt with a WHERE clause would just eliminate one source row for id = 3 in your example (the one with colID = 1), leaving two more for the same id. So we still get a row for id = 3 in the result after aggregating.
But since we have no row with colID = 1, we get an empty string (note: not a NULL value!) for fn in the result for id = 3.
A faster solution in Postgres would be to use crosstab(). Details:
PostgreSQL Crosstab Query
Other RDBMS
While EVERY is defined in the SQL:2008 standard, many RDBMS do not support it, presumably because some of them have shady implementations of the boolean type. (Not dropping any names like "MySQL" or "Oracle" ...). You can probably substitute everywhere (including Postgres) with:
SELECT id
, max(case when colID = 1 then value else '' end) AS fn
, max(case when colID = 2 then value else '' end) AS ln
, max(case when colID = 3 then value else '' end) AS jt
FROM tbl
GROUP BY id
HAVING count(*) = count(value);
Because count() doesn't count NULL values. In MySQL there is also bit_and().
More under this related question:
Is there any equivalent to Postgresql EVERY aggregate function on other RDBMS?
It works in Oracle because Oracle handles NULL incorrectly in that NULL and '' are the same. The other databases don't do this because it is wrong. NULL is unknown, versus '' which is just a blank, empty string.
So if your where clause said something like WHERE (fn IS NOT NULL or fn <> '') you would probably get further.
I think this is a case where a HAVING clause will do what you need.
SELECT id, max ... (same stuff as before)
FROM tbl
GROUP by id
HAVING fn IS NOT NULL
AND ln IS NOT NULL
AND jt IS NOT NULL