Error in sql query when using contains in aggregate expression - sql

Query:
SELECT
c,
COUNT
( WHEN a='11' AND contains(b,'aa') THEN 1 ELSE NULL END
) as total
from x
group by c
Error:
Full-text predicates cannot appear in an aggregate expression. Place
the aggregate expression in a subquery.
I am using contains because, it uses the index when searching in text, also the query is like that only, so i have to put it in aggregate expression only.... please suggest..

Try this one -
SELECT total = COUNT(
CASE WHEN a = '11'
AND CONTAINS(b, 'aa') THEN 1
END)
FROM x

CONTAINS can appear only in a WHERE clause
SELECT
c,
COUNT(ContainsResult) AS total
FROM
(
SELECT
c, CASE WHEN a='11' THEN 1 ELSE NULL END AS ContainsResult
from
x
WHERE
contains(b,'aa')
UNION ALL
SELECT
c, NULL
from
x
WHERE
NOT contains(b,'aa')
) X1
GROUP BY
c

Related

Not a group expression: troubleshooting an Oracle query

Oracle query
I have a column value with hardcoded value 'N/A' and other char values as well. I need to write a select query to get the min of this column grouping the other set of columns.. but the challenge is i need to replace the hard coded value of 'N/A' with another character 'Abc' along with min function
Option 1: nvl won't work as the value is hardcoded
Option 2: decode in the select statement along with min clause in the decode list, and group by clause with the other columns used in the select list
However, getting an error
ORA-00979 : not a group expression.
Example :
Select a, b, decode(z,'N/A','abc',min(z))
From table 1, table 2
Where table 1.p=table2.q
Group by a,b
Having c.table1 >= table2.d
You should be using DECODE inside the MIN function, not the other way around. But, I would probably just use a single CASE expression here:
SELECT
a,
b,
MIN(CASE WHEN z = 'N/A' THEN 'abc' ELSE z END) AS min_value
FROM table1 t1
INNER JOIN table2 t2
ON t1.p = t2.q
GROUP BY
a,
b;
The above CASE expression is just taking the minimum value of z for each group, with the only difference between MIN(z) being that should the value be N/A, it would be treated as abc.

Only one expression can be specified in the select list w

I am having problem in part of my code anyway to do this
Only one expression can be specified in the select list when the subquery is not introduced with EXISTS. The update part is working but how to use insert into to calculate if a condition is not meant it will insert.
IF
/* CHECKLIST TO UPDATE*/
(NOT EXISTS
(SELECT *
FROM ENERGY.D_ENERGY_REFERENCE D_ENERGY_REFERENCE
,ENERGY.D_CHECK_LIST D_CHECK_LIST
WHERE D_ENERGY_REFERENCE.ID = D_CHECK_LIST.ID
AND D_ENERGY_REFERENCE.REFERENCE = 19051
)
)
BEGIN
INSERT INTO DB.D_ENERGY_REFERENCE(ID, REFERENCE_NO, REFERENCE,VALUE_INTEGER)
(SELECT ID,
(SELECT ISNULL(MAX(REFERENCE_NO), 0) + 1 FROM DB.D_ENERGY_REFERENCE),
19051, (SELECT D_CHECK_LIST.ID,
CASE
WHEN CAST(COUNT(CASE WHEN D_CHECK_LIST.EVALUATION NOT IN (0,1) THEN EVALUATION ELSE NULL END) AS FLOAT) = 0 THEN NULL
ELSE
(
CAST(COUNT(CASE WHEN D_CHECK_LIST.EVALUATION IN (2, 3, 50001, 50003, 50004, 50005, 50006, 50020, 50027, 50028) THEN EVALUATION ELSE NULL END) AS FLOAT)
/
CAST(COUNT(CASE WHEN D_CHECK_LIST.EVALUATION NOT IN (0,1) THEN EVALUATION ELSE NULL END) AS FLOAT)
) * 100
END FROM DB.D_CHECK_LIST
GROUP BY D_CHECK_LIST.ID)
FROM DB.D_ENERGY_REFERENCE D_ENERGY_REFERENCE
WHERE D_ENERGY_REFERENCE.ID = ID AND D_ENERGY_REFERENCE.REFERENCE = 19051
GROUP BY D_ENERGY_REFERENCE.ID
)
END
Can you please check this following part in the sub query of your script-
.......
19051,
(
SELECT
D_CHECK_LIST.ID, -- This is the column 1
CASE
WHEN -- Here you are generating column 2 in the sub query
......
)
Here you are selecting 2 column - one is "D_CHECK_LIST.ID" and other one is generation through CASE WHEN statement. I think you should SELECT any 1 column from those 2 column. If both are required, you can use separate Sub query for that.
The ERROR code "Only one expression can be specified in the select list when the subquery is not introduced with EXISTS" is self explanatory that you can not implement a Sub Query with more than 1 column selected unless the Sub Query is using inside EXISTS method.

SQL code to count only duplicates where all instances of the duplicate are null

I have a large data set with duplicate reference numbers (reference duplications range from 0 to 37 times). I want to count the number of references only where all instances are null in two columns. So using the table below, the code should return 1 because only Reference Code 3 has all null values, and the duplicates should only be counted once.
I would be grateful for any help.
This involves two steps: (1) isolate all the distinct pairs of values that only have null; (2) count each one once. One way to express this in a query is:
SELECT COUNT(*) FROM
(
SELECT refnum FROM #ref
GROUP BY refnum
HAVING MIN(colA) IS NULL
AND MIN(colB) IS NULL;
) AS x;
Use aggregation to get the codes:
select code
from t
group by code
having max(a) is null and max(b) is null;
If you want the count, use a subquery:
select count(*)
from (select code
from t
group by code
having max(a) is null and max(b) is null
) t;
With conditional aggregation:
select
refcode
from referencecodes
group by refcode
having sum(case when (a is null and b is null) then 0 else 1 end) = 0
The above will return the codes with only null values in a and b.
If you want the number of codes:
select count(r.refcode) from (
select
refcode
from referencecodes
group by refcode
having sum(case when (a is null and b is null) then 0 else 1 end) = 0
) r
Or with EXISTS:
select
count(distinct r.refcode)
from referencecodes r
where not exists (
select 1 from referencecodes
where (refcode = r.refcode) and (a is not null or b is not null)
)
See the demo

Filter if values provided otherwise return everything

Say I have a table t with 2 columns:
a int
b int
I can do a query such as:
select b
from t
where b > a
and a in(1,2,3)
order by b
where 1,2,3 is provided from the outside.
Obviously, the query can return no rows. In that case, I'd like to select everything as if the query did not have the and a in(1,2,3) part. That is, I'd like:
if exists (
select b
from t
where b > a
and a in(1,2,3)
)
select b
from t
where b > a
and a in(1,2,3)
order by b
else
select b
from t
where b > a
order by b
Is there a way to do this:
Without running two queries (one for exists, the other one the actual query)
That is less verbose than repeating queries (real queries are quite long, so DRY and all that stuff)
Using NOT EXISTS with a Sub Query to Determine if condition exists
SELECT b
FROM
t
WHERE
b > a
AND (
NOT EXISTS (SELECT 1 FROM #Table WHERE a IN (1,2,3))
OR a IN (1,2,3)
)
ORDER BY
b
The reason this works is because if the condition exists then the OR statement will include the rows and if the condition does not exist then the NOT EXISTS will include ALL rows.
Or With Common Table Expression and window Function with Conditional Aggregation.
WITH cte AS (
SELECT
b
,CASE WHEN a IN (1,2,3) THEN 1 ELSE 0 END as MeetsCondition
,COUNT(CASE WHEN a IN (1,2,3) THEN a END) OVER () as ConditionCount
FROM
t
)
SELECT
b
FROM
cte
WHERE
(ConditionCount > 0 AND MeetsCondition = 1)
OR (ConditionCount = 0)
ORDER BY
b
I find it a bit "ugly". Maybe it would be better to materialize output from your query within a temp table and then based on count from temp table perform first or second query (this limits accessing the original table from 3 times to 2 and you will be able to add some flag for qualifying rows for your condition not to repeat it). Other than that, read below . . .
Though, bear in mind that EXISTS query should execute pretty fast. It stops whether it finds any row that satisfies the condition.
You could achieve this using UNION ALL to combine resultset from constrained query and full query without constraint on a column and then decide what to show depending on output from first query using CASE statement.
How CASE statement works: when any row from constrained part of your query is found, return resultset from constrainted query else return everything omitting the constraint.
If your database supports using CTE use this solution:
with tmp_data as (
select *
from (
select 'constraint' as type, b
from t
where b > a
and a in (1,2,3) -- here goes your constraint
union all
select 'full query' as type, b
from t
where b > a
) foo
)
SELECT b
FROM tmp_data
WHERE
CASE WHEN (select count(*) from tmp_data where type = 'constraint') > 0
THEN type = 'constraint'
ELSE type = 'full query'
END
;

Referring to results of a sub query in main query

I have a sub query that returns one column, showing as GroupType, I then want to do a CASE function on this result within the main query, however I get an invalid column name when using the CASE statement.
Can i do this in SQL to do I have to refer to it by a different name
SELECT CASE
WHEN
(
SELECT column
FROM othertable
) = 1
THEN '1'
ELSE '2'
END
FROM mytable
To reuse the subquery result:
SELECT subvalue, CASE subvalue WHEN 1 THEN 1 ELSE 2 END
FROM (
SELECT (
SELECT column
FROM othertable
) AS subvalue
FROM mytable
) q