How to search for column name in range or column is null - sql

I have an query that I am writing where i have a table containing a list of ages, this column can have NULLS. I have been trying to get a result containing users ages 18+ and if the users age is NULL i would like that result as well. Here is a simplified version of what im trying to do below, and the results.
SELECT * FROM TABLE WHERE (Table.Column >= 18 OR Table.Column IS NULL)
-Returns users of all ages and nulls
SELECT * `FROM TABLE WHERE ((Table.Column >= 18) OR (Table.Column IS NULL))
-Returns users of all ages and nulls
SELECT * FROM TABLE WHERE (Table.Column >= 18 NOT BETWEEN 1 AND 17)
-Returns only users 18+, does not return NULLS
SELECT * `FROM TABLE WHERE ((Table.Column >= 18)
-Returns only users 18+, does not return NULLS
Any insight to what may be happening would be a blessing. This is part of a 1300 line query and this is the best i am able to simplify it. I may need you to keep in mind there may be other things going on which im un-able to explain and maybe a hacky work around is in order.
To go into further details, in psuedo code the entire query is as below.
SELECT ColumnA, ColumnB,
CASE
WHEN (Condition 1),
WHEN (Condition 2)
ELSE 'N/A' END AS [Complete],
CASE
WHEN (Condition 1),
WHEN (Condition 2)
ELSE Column END AS [Column],
ColumnC, ColumnD
FROM
LEFT OUTER JOIN Table A on A.Column = B.Column
LEFT OUTER JOIN Table C on A.Column = B.Column
LEFT OUTER JOIN Table D on A.Column = C.Column
WHERE (
Condition1,
and Condition2,
and (Table.Column >= 18 OR Table.Column IS NULL)
)UNION
SELECT
MAX([column]) AS [column],
MAX([MyColumn] AS [My Column],
FROM (
SELECT
column],
MyColumn,
CASE
WHEN (Condition 1),
WHEN (Condition 2)
else 'N/A' end as [Complete]
CASE
WHEN (Condition 1),
WHEN (Condition 2)
ELSE Column END AS [Column],
Column3
WHERE (Condition1)
AND Condition2
)
and (Table.Column >= 18 OR Table.Column IS NULL)
GROUP BY [ColumnName]
UNION
SELECT * FROM TABLE

For my case I had to put the three tables which were being union together in 3 different sub queries, from there I put my where clause
SELECT A.* FROM (
Select * FROM TABLE1
) A
WHERE (A.ColumnOne >= 18 OR ColumnOne IS NULL)
UNION
SELECT B.* FROM (
Select * FROM TABLE2
) B
WHERE (B.ColumnOne >= 18 OR ColumnOne IS NULL)
UNION
SELECT C.* FROM (
Select * FROM TABLE2
) C
WHERE (C.ColumnOne >= 18 OR ColumnOne IS NULL)

Related

Use result from case statement in another case statement in oracle

I have a view which contains a cast statement for one column. This cast statement contains a case statement. This statement works. The result of this statement is 1, 2, or 3.
From here, I need to use the result from the previous case statement (I used a WITH statement and it doesn't work) to determine the value of the column. A simple case statement that assigns yes, no or null to the above statement's value (1,2, or 3)
ANY help is appreciated. Thank you.
Example using pseudo-code:
CAST (
WITH case_output
AS(
SELECT
CASE
WHEN EXISTS
(select from table where blah blah)
THEN
(select column from that table)
ELSE
(select from some another table)
END
)
CASE
WHEN case_output = 1
THEN 'Yes'
WHEN case_output = 2
THEN 'No'
else
NULL
AS VARCHAR2 (10))
column_name,
.... [rest of query]
You're mixing up the query name and the column name of the WITH clause. For example, it's
WITH my_query AS (SELECT c1 AS my_column FROM t1)
SELECT my_column FROM my_query;
Secondly, you'll always need a FROM clause in Oracle's SQL. Use the dummy table DUAL as stand-in:
SELECT CASE WHEN ... THEN END AS my_column
FROM DUAL;
Minimal working example:
CREATE TABLE t1 (c1 INT);
CREATE TABLE t2 (c2 INT);
INSERT INTO t1 VALUES (1);
INSERT INTO t2 VALUES (2);
WITH case_query AS (
SELECT CASE WHEN EXISTS (SELECT * FROM t1 WHERE c1=100)
THEN (SELECT c1 FROM t1)
ELSE (SELECT c2 FROM t2)
END AS case_output
FROM dual)
SELECT CASE case_output
WHEN 1 THEN 'Yes'
WHEN 2 THEN 'No'
ELSE NULL
END second_case_output
FROM case_query;

Search SQL and return true or false

I have a table that has thousands of rows in. I need to check if certain values exists in the table or not.
I want to list all the bar codes I am searching with a flag of true or false returned if there is one.
I have come up with this so far:
SELECT CASE WHEN EXISTS (
SELECT *
FROM TABLE
WHERE Coulmn in ('a','b', 'c', 'd', 'e', 'f', 'g')
)
THEN CAST(1 AS BIT)
ELSE CAST(0 AS BIT) END
This however just returns a value of 1.
So in the table I have
coulmn
----------
A
B
D
E
F
G
I want to do a search that returns the following
Coulmn | Exsists
-----------------
A | True
B | True
C | False
D | True
E | True
F | True
G | True
You can use a query like the following:
SELECT t1.v,
CASE WHEN t2.col IS NOT NULL THEN 'true' ELSE 'false' END AS Exists
FROM (
SELECT 'a' AS v UNION ALL SELECT 'b' UNION ALL SELECT 'c' UNION ALL SELECT 'd'
UNION ALL SELECT 'e' UNION ALL SELECT 'f' UNION ALL SELECT 'g') AS t1
LEFT JOIN mytable AS t2 ON t1.v = t2.col
This works:
SELECT *, CASE WHEN (Column in ('1','2')) THEN CAST(1 AS BIT) ELSE CAST(0 AS BIT) END AS result_field
FROM TABLE;
NOTE: Tested in PostgreSQL
As it's written, the outer select is select case when exists () then 1 else 0 end... so it is only going to return one row. The outer select must include "Column" AND "Exists" (select column, ...) to return two columns.
A "where" clause will never return a "false" like this, though, because "column" has to be in a real table for the query to actually return it. As #jarlh says, you'll need a helper table to store the columns you're looking for:
Create table SearchColumns (SearchColumn char(1));
insert into SearchColumns (SearchColumn)
values ('A'), ('B'), ('C'), ('D'), ('E'), ('F'), ('G'), ('H')
Then you can do the If Exists to your table from that table to see which values are in or not in:
select SearchColumn, case when exists
(select * from TABLE where Table.Column = SearchColumns.SearchColumn)
then 'True' else 'False' end as ExistsStatus
from SearchColumns
I think that will get you what you want. This gets a) Only one record per column no matter how many times it occurs in your table and b) "True" and "False" for every column value you're looking for. If you really wanted a Bit, you can use 0 and 1 and the casting from the original query, but they actually show "0" and "1"; and c) this should work no matter how many values you have.
(Note, I assumed some of those were spelling errors, so I made adjustments, but they were consistent so I'm not certain).
With the help form above I created a temp table and then implemented one of the soultions shared.
CREATE TABLE #Temp
(
Barcode VARCHAR (100)
)
INSERT INTO #Temp
VALUES
(1),
(2),
(3),
(4 )
select barcode, case when exists
(select * from CIPKORHHTProductDetails where CIPKORHHTProductDetails.Barcode = #temp.barcode)
then 'True' else 'False' end as ExistsStatus
from #temp order by ExistsStatus DESC

How to check whether certain tables are empty?

How can I check whether certain datatables (e.g. "tableA", "tableB" & "tableC") are empty in one query (SQL Server)?
Expected result:
The most important for me is to have ONE result.
It could be true (if all tables are empty) vs false.
Another possibility is the sum of all entries over all tables like 0 (if all tables are empty) or otherwise n.
Example
There are three tables in database: table1, table2 and table3.
All tables are empty. --> Expected result: 0
Table1 has 3 rows, table2 has 0 rows, table3 has 1 row. --> Expected result: 4.
You can get the counts from the tables using union all:
select 'a', count(*) from a union all
select 'b', count(*) from b union all
select 'c', count(*) from c;
However, the fastest way is to use exists:
select (case when not exists (select 1 from a) then 1 else 0 end) as a_is_empty,
(case when not exists (select 1 from b) then 1 else 0 end) as b_is_empty,
(case when not exists (select 1 from c) then 1 else 0 end) as c_is_empty
EDIT:
If you want the total rows in the three tables, just add them up:
select sum(cnt)
from (select 'a', count(*) as cnt from a union all
select 'b', count(*) from b union all
select 'c', count(*) from c
) abc;
I would be wary about using system tables for this operation, if you need exact, up-to-date results. System tables are great in a static environment, where the tables aren't changing, but I suspect your environment is more dynamic.
You also can use this DMV which will query the Count from CACHE only..
SELECT SUM(row_count) AS rows
FROM sys.dm_db_partition_stats
where object_name(object_id) in ('table1','tab1e2')
group by OBJECT_NAME(object_id)
Update as per question:
;with cte
as
(SELECT SUM(row_count) AS rows
FROM sys.dm_db_partition_stats
where object_name(object_id) in ('table1','tab1e2')
group by OBJECT_NAME(object_id))
select sum(rows) as rows from cte
hope below query help you.
SELECT
SCHEMA_NAME(SOS.SCHEMA_ID) + '.' + (SOS.NAME) AS [Table Name]
, (SPS.Rows) AS [Row Count]
, [Heap / Clustered Table] = CASE SPS.INDEX_ID WHEN 0 THEN 'HEAP' ELSE 'CLUSTERED' END
FROM
sys.objects AS SOS
INNER JOIN sys.partitions AS SPS
ON SOS.object_id = SPS.object_id
WHERE
SOS.type = 'U'
AND SPS.index_id < 2
and SPS.Rows =0
ORDER BY [Table Name]
Please Mark me as answer if my post helps you.
Regards
ChetanV

Select rows having the same features than others

I've the following table with 3 columns: Id, FeatureName and Value:
Id FeatureName Value
-- ----------- -----
1 AAA 10
1 ABB 12
1 BBB 12
2 AAA 15
2 ABB 12
2 ACD 7
3 AAA 10
3 ABB 12
3 CCC 12
.............
Each Id has different features and each Feature has a value for that Id.
I need to write a query which gives me the Ids that have exactly the same features and values than a given one, but only taking into account those whose name starts with 'A'. For example, in the top table, I can use that query to search for all the Ids that have the same features. For example, features with values where Id=1 would result Id=3 with same features starting with 'A' and same values for these features.
I found a couple of different ways to do this, but all of them go very slow when the table has lots of rows (more than hundred of thousands)
The way I obtain the best performance is using the next query:
select a2.Id
from (select a.FeatureName, a.Value
from Table1 a
where a.Id = 1) a1,
(select a.Id, a.FeatureName, a.Value
from Table1 a
where a.FeatureName like 'A%') a2
where a1.FeatureName = a2.FeatureName
and a1.value = a2.value
group by a2.Id
having count(*) = 2
intersect
select a.Id
from Table1 a
where a.FeatureName like 'A%'
group by a.Id
having count(*)= 2
where #nFeatures is the number of features starting by 'A' in Id=1. I counted them before calling this query. I make the intersection to avoid results that have the same parameters than Id=1 but also some others whose name starts with 'A'.
I think that the slowest part is the second subquery:
select a.Id, a.FeaureName, a.Value
from MyTable a
where a.FeatureName = 'A%'
but I don't know how to make it faster. Maybe I will have to play with the indexes.
Any idea of how could I write a fast query for this purpose?
So you want all rows where the combination of FeatureName and Value is not unique? You can use EXISTS:
SELECT t.*
FROM dbo.Table1 t
WHERE t.FeatureName LIKE 'A%'
AND EXISTS(SELECT 1 FROM dbo.Table1 t2
WHERE t.Id <> t2.ID
AND t.FeatureName = t2.FeatureName
AND t.Value = t2.Value)
Demo
how could I write a fast query for this purpose?
If it's not fast enough create an index on FeatureName + Value.
I tried to eliminate the join with MyTable again to select the data for the ID's that have matching FeatureName and Value values. Here's the query:
with joined_set as
(
SELECT
mt1.*, mt2.id as mt2_id, mt2.featurename as mt2_FeatureName, mt2.value as mt2_value
from
(
select *
from mytable
where featurename like 'A%'
) mt1
left join
(
select *
from mytable
where featurename like 'A%'
) mt2
on mt2.id <> mt1.id and mt2.FeatureName = mt1.featurename and mt2.value = mt1.value
)
select distinct id
from joined_set
where id not in
(select id
from joined_set
group by id
having SUM(
CASE
WHEN mt2_id is null THEN 1
ELSE 0
END
) <> 0
);
Here is the SQL Fiddle demo. It has an extra condition in the inline view mt2, to perform this search only for id = 1.
I'm a little dense this morning, I'm not sure if you wanted just the ID's or...
Here's my take on it...
You could probably move the where FeatureName like 'A%' into the inner query to filter the data on the initial table scan.
with dupFeatures (FeatureName, Value, dupCount)
as
(
select FeatureName, Value, count(*) as dupCount from MyTable
group by FeatureName, Value
having count(*) > 1
)
select MyTable.Id, dupFeatures.FeatureName,dupFeatures.Value
from dupFeatures
join MyTable on (MyTable.FeatureName = dupFeatures.FeatureName and
MyTable.Value = dupFeatures.Value )
where dupFeatures.FeatureName like 'A%'
order by FeatureName, Value, Id
A general solution is
With Rows As (
select id
, FeatureName
, Value
, rows = Count(id) OVER (PARTITION BY id)
FROM test
WHERE FeatureName LIKE 'A%')
SELECT a.id aID, b.id bID
FROM Rows a
INNER JOIN Rows b ON a.id < b.id and a.FeatureName = b.FeatureName
and a.rows = b.rows
GROUP BY a.id, b.id
ORDER BY a.id, b.id
to limit the solution to a group just add a WHERE condition on the main query for a.ID. The CTE is needed to get the correct number of rows for each id
SQLFiddle demo, in the demo I changed little the test data to have a another couple of ID with only one of the FeatureName of 1 and 3

SQL using CASE in SELECT with GROUP BY. Need CASE-value but get row-value

so basicially there is 1 question and 1 problem:
1. question - when I have like 100 columns in a table(and no key or uindex is set) and I want to join or subselect that table with itself, do I really have to write out every column name?
2. problem - the example below shows the 1. question and my actual SQL-statement problem
Example:
A.FIELD1,
(SELECT CASE WHEN B.FIELD2 = 1 THEN B.FIELD3 ELSE null FROM TABLE B WHERE A.* = B.*) AS CASEFIELD1
(SELECT CASE WHEN B.FIELD2 = 2 THEN B.FIELD4 ELSE null FROM TABLE B WHERE A.* = B.*) AS CASEFIELD2
FROM TABLE A
GROUP BY A.FIELD1
The story is: if I don't put the CASE into its own select statement then I have to put the actual rowname into the GROUP BY and the GROUP BY doesn't group the NULL-value from the CASE but the actual value from the row. And because of that I would have to either join or subselect with all columns, since there is no key and no uindex, or somehow find another solution.
DBServer is DB2.
So now to describing it just with words and no SQL:
I have "order items" which can be divided into "ZD" and "EK" (1 = ZD, 2 = EK) and can be grouped by "distributor". Even though "order items" can have one of two different "departements"(ZD, EK), the fields/rows for "ZD" and "EK" are always both filled. I need the grouping to consider the "departement" and only if the designated "departement" (ZD or EK) is changing, then I want a new group to be created.
SELECT
(CASE WHEN TABLE.DEPARTEMENT = 1 THEN TABLE.ZD ELSE null END) AS ZD,
(CASE WHEN TABLE.DEPARTEMENT = 2 THEN TABLE.EK ELSE null END) AS EK,
TABLE.DISTRIBUTOR,
sum(TABLE.SOMETHING) AS SOMETHING,
FROM TABLE
GROUP BY
ZD
EK
TABLE.DISTRIBUTOR
TABLE.DEPARTEMENT
This here worked in the SELECT and ZD, EK in the GROUP BY. Only problem was, even if EK was not the designated DEPARTEMENT, it still opened a new group if it changed, because he was using the real EK value and not the NULL from the CASE, as I was already explaining up top.
And here ladies and gentleman is the solution to the problem:
SELECT
(CASE WHEN TABLE.DEPARTEMENT = 1 THEN TABLE.ZD ELSE null END) AS ZD,
(CASE WHEN TABLE.DEPARTEMENT = 2 THEN TABLE.EK ELSE null END) AS EK,
TABLE.DISTRIBUTOR,
sum(TABLE.SOMETHING) AS SOMETHING,
FROM TABLE
GROUP BY
(CASE WHEN TABLE.DEPARTEMENT = 1 THEN TABLE.ZD ELSE null END),
(CASE WHEN TABLE.DEPARTEMENT = 2 THEN TABLE.EK ELSE null END),
TABLE.DISTRIBUTOR,
TABLE.DEPARTEMENT
#t-clausen.dk: Thank you!
#others: ...
Actually there is a wildcard equality test.
I am not sure why you would group by field1, that would seem impossible in your example. I tried to fit it into your question:
SELECT FIELD1,
CASE WHEN FIELD2 = 1 THEN FIELD3 END AS CASEFIELD1,
CASE WHEN FIELD2 = 2 THEN FIELD4 END AS CASEFIELD2
FROM
(
SELECT * FROM A
INTERSECT
SELECT * FROM B
) C
UNION -- results in a distinct
SELECT
A.FIELD1,
null,
null
FROM
(
SELECT * FROM A
EXCEPT
SELECT * FROM B
) C
This will fail for datatypes that are not comparable
No, there's no wildcard equality test. You'd have to list every field you want tested individually. If you don't want to test each individual field, you could use a hack such as concatenating all the fields, e.g.
WHERE (a.foo + a.bar + a.baz) = (b.foo + b.bar + b.az)
but either way, you're listing all of the fields.
I might tend to solve it something like this
WITH q as
(SELECT
Department
, (CASE WHEN DEPARTEMENT = 1 THEN ZD
WHEN DEPARTEMENT = 2 THEN EK
ELSE null
END) AS GRP
, DISTRIBUTOR
, SOMETHING
FROM mytable
)
SELECT
Department
, Grp
, Distributor
, sum(SOMETHING) AS SumTHING
FROM q
GROUP BY
DEPARTEMENT
, GRP
, DISTRIBUTOR
If you need to find all rows in TableA that match in TableB, how about INTERSECT or INTERSECT DISTINCT?
select * from A
INTERSECT DISTINCT
select * from B
However, if you only want rows from A where the entire row matches the values in a row from B, then why does your sample code take some values from A and others from B? If the row matches on all columns, then that would seem pointless. (Perhaps your question could be explained a bit more fully?)