subquery or passthrough; SQL Server 2008r2 - sql-server-2008

I have an Access 2000 query that works on linked tables from SQL Server 2008 R2. I need to write it as a view or pass through query:
`
SELECT Max(CLng((Mid([tbl1]![ID],5)))) AS lastnumberused
FROM [tbl1]
WHERE ((([tbl1]![ID]) Like "OODD*" And ([tbl1]![ID]) Not Like "OODDid*" And ([tbl1]![ID]) Not Like "*x") AND ((CLng((Mid([tbl1]![ID],5))))<1000000));
`
So what I'm looking for is the max number under 1000000 that begins with OODD% but not OODDID%. Also the record cannot end with 'x'.
My code in TSQL for SQL Server looks like this and doesn't work...
`
SELECT
convert (int, (substring(tblMain.BarcodeID,5,10))) as X1, [ID]
FROM tblMain
WHERE ([tbl1]![ID] LIKE N'OODD%')
AND ([tbl1]![ID] NOT LIKE N'%x%')
AND ([tbl1]![ID] NOT LIKE N'OODDID%')
Select MAX (x1)+1
from bar1
where (x1<1000000)
`
suggestions?
thanks,H
Update 15june2013
WITH T1 (number)
AS
(SELECT substring(tbl1.ID,5,10)
FROM tblMain AS tbl1
WHERE (ID LIKE N'oodd%')
AND (ID NOT LIKE N'%x%')
AND (ID NOT LIKE N'ooddID%'))
SELECT (cast((number)as int)) FROM T1
This works and returns 561770 rows.
With T1(number)
as(SELECT cast(SUBSTRING(ID, 5, 7)as int)
FROM tblMain as tbl1
WHERE (tbl1.ID LIKE N'oodd%')
AND (tbl1.ID NOT LIKE N'%x%')
AND (tbl1.ID NOT LIKE N'%ooddID%')
AND ISNUMERIC(SUBSTRING(tbl1.ID,5,10))=1)
Select max(number) from T1
Also works but returns a number above 1000000
When a where statement is added the following code includes records that should have been excluded in the previous statement.
With T1(number)
as(SELECT cast(SUBSTRING(ID, 5, 7)as int)
FROM tblMain as tbl1
WHERE (tbl1.ID LIKE N'oodd%')
AND (tbl1.ID NOT LIKE N'%x%')
AND (tbl1.ID NOT LIKE N'%ooddID%')
AND ISNUMERIC(SUBSTRING(tbl1.ID,5,10))=1)
Select max(number) from T1
where x1 <1000000

The WHERE clause contains a [tbl1] table which is not present in the FROM clause. You should either change it to tblMainBee or add an "tbl1" alias in the FROM clause with AS.
Also, you have two unconnected SELECT statements, instead of a single one. Again, in the second SELECT, there is a bar1 table which doesn't appear anywhere else... is it correct?
Another error is that you cannot use "!" to separate table name and field name. You must use a dot.
Finally, there are issues when trying to convert the data type. You don't need it since comparison between strings also works.
Your access SELECT statement is much more straightforward.
Try with
WITH T1(number) AS (
SELECT substring(tbl1.ID,5,LEN(tbl1.ID)-4)
FROM tblMainBee as tbl1
WHERE ([tbl1].[ID] LIKE N'OODD%')
AND ([tbl1].[ID] NOT LIKE N'%x%')
AND ([tbl1].[ID] NOT LIKE N'OODDID%')
AND (IsNumeric(substring(tbl1.ID,5,LEN(tbl1.ID)-4)) = 1)
)
SELECT max(convert(bigint,number)) FROM T1 WHERE number < 1000000;
The second type conversion is implicit since 1000000 is numeric. The first one is necessary. Otherwise, it would consider '12346' bigger than '123421'.
Comparison between strings only works if they have fixed length.
Regards,

Try this
select MAX(CAST(SUBSTRING(ID,5,9) as INT))+1
from tblMainBee
where
ID Like 'OODD%'
AND ID Not Like 'OODDid%'
AND ID Not Like '%x'
AND ISNUMERIC(SUBSTRING(ID,5,9))=1
AND CAST(SUBSTRING(ID,5,9) as INT)<1000000

Related

WHERE x IN works with a single value, not with multiple on json

There's a hard to understand issue with querying on a json field in MySQL. The data column is of type json.
The following query works perfectly fine
SELECT * FROM `someTable` WHERE data->'$.someData' in ('A')
However the following one returns nothing.
SELECT * FROM `someTable` WHERE data->'$.someData' in ('A','B')
Funnily enough this also works:
SELECT * FROM `someTable` WHERE data->'$.someData'='A' OR data->'$.someData'='B'
I'm clueless as to why this happens. I originally thought that WHERE x IN executed in a json query format might be doing something like && but even if the values are ('A','A') it still returns nothing which essentially shows that more than one value in WHERE x IN wont work.
SAMPLE DATA (any would do really)
id | data (json)
1 | {"someData":"A"}
2 | {"someData":"B"}
Too long for a comment...
This seems to be related to an optimisation MySQL is performing when there is only one value in the IN expression (probably converting it to an a = b expression) and then it ignoring quotes. Strictly speaking,
SELECT *
FROM `someTable`
WHERE data->'$.someData' in ('A')
or
SELECT *
FROM `someTable`
WHERE data->'$.someData' = 'A'
should return no data because
SELECT data->'$.someData'
FROM someTable;
returns
"A"
"B"
which is not the same as A. You need to use JSON_UNQUOTE (or if you have MySQL 5.7.13 or later the ->> operator) to get the actual value of the someData key:
SELECT JSON_UNQUOTE(data->'$.someData') FROm someTable;
SELECT data->>'$.someData' FROm someTable;
which gives
A
B
which then works fine with an IN expression:
SELECT *
FROM `someTable`
WHERE JSON_UNQUOTE(data->'$.someData') in ('A','B')
-- or use WHERE data->>'$.someData' in ('A','B')
Output:
id data
1 {"someData":"A"}
2 {"someData":"B"}
Demo on dbfiddle
You could try using a join on a subquery instead of a IN clause
SELECT *
FROM `someTable` s
INNER JOIN (
select 'A' col
union
select 'B'
) t ON t.col = s.data->'$.someData

Find out values which are not available in table

Let assume Following simple table
Col1
======
one
two
Let assume Following simple query
Select count(*) from TABLE_A where Col1 in ('one','two','three','four')
In above query it will produce following result
2
Now I want to find out what are the values in IN- condition which is not available in table_A.
How to find out that values which are not available in table?
like below result
three
four
Above queries only example. In my real time query in have 1000 values in IN-Condition.
Working Database : DB2
This is the one of the work around to achieve your expectation.
Instead of hard-coding the values in IN condition, you can move those values in to a table. If it done simply using LEFT JOIN with NULL check you can get the not matching values.
SELECT MR.Col1
FROM MatchingRecords MR -- here MatchingRecords table contains the IN condition values
LEFT JOIN Table_A TA ON TA.Col1 = MR.Col1
WHERE TA.Col1 IS NULL;
Working DEMO
If the values are to be listed in the statement string rather than stored in a table, then perhaps a revision to the syntax being used for that list of values currently being composed [apparently, from some other input than a TABLE] for the IN predicate can be effected? The following revised syntax for a list of values could be used both for the original aggregate query [shown immediately below as the first of two queries], and for the query for which the how-to-code is being asked [the second of the two queries below]:
Select count(*)
from TABLE_A
where Col1 in ( values('one'),('two'),('three'),('four') )
; -- report from above query follows:
COUNT ( * )
2
[Bgn-Edit 05-Aug-2016: adding this text and example just below]Apparently at least one DB2 variant balks at unnamed columns for the derived table, so the query just below names the column; I chose COL1, so as to match the name from the actual TABLE, but that should not be necessary. The (col1) is added to the original query that remains from the original pre-edit version; that version remains after this edit\insertion and is missing the (col1) added here:
select *
from ( values('one'),('two'),('three'),('four') ) as x (col1)
except ( select * from table_a )
; -- report from above query follows:
COL1
three
four
The following is the original query given, for which the comment below suggests a failure for an unnamed column when run on some unstated DB2 variant; I should have noted that this SQL query functions without error, on DB2 for i 7.1
[End-Edit 05-Aug-2016]
select *
from ( values('one'),('two'),('three'),('four') ) as x
except ( select * from table_a )
; -- report from above query follows:
VALUES
three
four

MySQL IF on Where clause

Is it possible to make a query that changes the where clause acording to some condition? For instance I want to select * from table1 where data is 19/July/2016 but if field id is null then do nothing, else compare id to something else. Like the query bellow?
Select * from table1 where date="2016-07-19" if(isnull(id),"",and id=(select * from ...))
Yes. This should be possible.
If we assume that date and id are references to columns in (the unfortunately named) table table1, if I'm understanding what you are attempting to achieve, we could write a query like this:
SELECT t.id
, t.date
, t....
FROM table1 t
WHERE t.date='2016-07-19'
AND ( t.id IS NULL
OR t.id IN ( SELECT expr FROM ... )
)
It would also be possible to incorporate the MySQL IF() and IFNULL() functions, if there's some requirement to do that.
As far as dynamically changing the text of the SQL statement after the statement is submitted to the database, no, that's not possible. Any dynamic changes to the SQL text would need to be done when the SQL statement is generated, before it is submitted to the database.
My personal preference would be to use a join operation rather than a IN (subquery) predicate.
I think you're trying too hard. If id is NULL that's equivalent to having a FALSE in the where clause. So:
Select * from table1 where date="2016-07-19" and id=(select * from ...)
Should only match the records you want. If id is NULL you get nothing.

SQL works fine until I add a SUBSTR to subquery, then it just hangs. Why?

I have two SQL tables, call them t1 and t2. Both have column names str_id. The str_id is typically a 10 digit string, but I have special str_ids that begin with 'sp' followed by a normal 10 digit str_id. I would like to select all the 'sp' str_ids from t1, remove the sp, and look up the str_id in t2. I tried this query:
Select
str_id,
desired_column
From
t2
Where
str_id in (
Select
substr(str_id, 3)
From
t1
Where
str_id Like 'sp%' and
other_column = 'my_value'
);
Syntactically, this command seems correct, but when I run it my SQL frontend just hangs. If I run the command without the SUBSTR, then it executes fine, but it doesn't return the results I want because all the str_ids have sp prefixed. Just for reference, the command that works is:
Select
str_id,
desired_column
From
t2
Where
str_id In (
Select
str_id
From
t1
Where
str_id Like 'sp%' and
other_column = 'my_value'
);
What can I do to fix the query above?
Show the EXPLAIN outputs of those two, but I assume with the normal one mysql is able to directy crossreference indexes, while the SUBSTR one requires creating an intermediate resultset, and checking each individual item from t2. Which is a nice example why prefixing values with significant data is about as bad as people storing delimited strings in 1 column: hard to work with.
So, you're saying that t2.str_id values do not contain the 'sp' prefix, while t1.str_id do? You may want to rethink your data model. I suspect that there is an index on t1.str_id that cannot be used when you are trying to match subst(t1.str_id,3) to t2.str_id.
Depending on the relative sizes of the tables, this may perform faster:
SELECT
str_id, desired_column
FROM
t2
WHERE
concat( 'sp' , str_id ) IN (
SELECT str_id FROM t1
WHERE str_id LIKE 'sp%' and other_column = 'my_value'
);
Edited my answer. Try running this instead
SELECT str_id,
(
SELECT desired_column
FROM t2
WHERE str_id = SUBSTR(t1.str_id, 3)
)
FROM t1
WHERE str_id LIKE 'sp%' AND other_column = 'my_value'

Counting the ratio mysql

Say I have the following table,
I would like to select the ratio of all the names that start with A to all the names that start with B
For example
Name
ABC
DEF
VVV
BBB
BCD
ZZZ
So the output would be 0.5. I want to call that output 'out'.
So the output should be
out
0.5
pretty much what I want is
Select count(*) from table where name like 'A%' / select count(*) from table where name like 'B%'
but in a single query.
You can do something like:
select
(select count(*) from table where name like 'a%') / (select count(*) from table where name like 'b%');
Here's a SQL Fiddle.
Note that if the divisor is zero, mySql will coalesce the zero into a null and the resulting value will be null. This is different than say, Oracle, which will throw a divisor is equal to zero exception.
Here's a SQL Fiddle showing this behavior, which you should probably trap and handle appropriately.
This query will do what you need:
SELECT ((SELECT COUNT(*) FROM `table` WHERE name LIKE 'A%') /
(SELECT COUNT(*) FROM `table` WHERE name LIKE 'B%')) AS `out`