Check if a value starts with one of the value of a column - sql

Hi I'd like to check if a value starts with one of the value of a another column.
t1 | t2
----------
3253 | 123
1234 | 000
9876 | 932
So here for example I should have True for the value 1234 because it starts with 123.
I should have false for the other values.
I can't find any solutions.
Thank you in advance for you help !
I already tried :
t1 LIKE (t2 || '%')
starts_with(t1,t2)
starts_with(t1, (select t2))

Using t1 LIKE (t2 || '%') should be able to get you close to what I think you need, however maybe you are just missing a bit of script logic?
Ignoring any platform specific language (I don't use Big Query), this is just to show the logic that might help you get the result you desire
With the data as:
create table my_table
(t1 number,
t2 number);
insert into my_table values(3253,123);
insert into my_table values(1234,000);
insert into my_table values(9876,932);
You can use a case statement wrapped in a sum to count the matches using like t2||'%. Any value in the resulting column that is 1 or greater should be read as True, and value of 0 as False.
SELECT a.t1,
Sum(CASE
WHEN a.t1 LIKE b.t2
|| '%' THEN 1
ELSE 0
END) AS starts_with
FROM my_table a,
my_table b
GROUP BY a.t1
This gives the output
T1 STARTS_WITH
9876 0
1234 1
3253 0

That works for me :
-- To match your example
WITH T (t1,t2) AS
(
SELECT * FROM (VALUES (3253,123),(1234,000),(9876,932))t(t1,t2)
)
-- What your query should like
SELECT TAB1.t1,TAB1.t2, Tab2.t2
FROM T AS Tab1
CROSS JOIN T AS Tab2
WHERE CAST(TAB1.t1 AS STRING) LIKE (CAST(TAB2.t2 AS STRING) + '%')

Another option to try
select * except(check),
regexp_contains(t1, check)
from (
select *, r'^' || string_agg(t2, '|') over() check
from your_table
)
if applied to sample data in your question - output is

Related

Filtering out values inside the field using SQL command

I have one table as below:
And I have another table as below:
Now, I want to filter out the image name from table 1-image description field and compare it with image name in the table 2 and return the image ID in the output table. So I want my output table like below:
Could someone please help on this.
You can use substring_index(). Assuming it is the last value:
select substring_index(image_description, 'image=', -1)
from t;
If it can be anywhere in a semicolon separated list:
select substring_index(substring_index(image_description, 'image=', -1), ';', 1)
from t;
Here is a db<>fiddle.
EDIT:
In Oracle, you would simply use regexp_replace():
select regexp_replace(image_description, '^.*image=([^;]+).*', '\1')
from t;
Here is a db<>fiddle for this version.
The rest is simply joining on the values.
It looks like you are using Oracle and not MySql, so try this query with a left join of table1 to table2 and the operator like:
select t1.Name, t2."image id"
from table1 t1 left join table2 t2
on t1."image description" like '%image="' || t2.image || '" />'
This will work for the sample data as you posted it, but if image="..." may appear anywhere inside the string then use:
on t1."image description" like '%image="' || t2.image || '"%'
See the demo.
Results:
> NAME | image id
> :--- | -------:
> x | 1
> b | null
> y | 2
> z | 2
> a | null
Assuming the values for column image_desc has always the same format that ends with the text pattern image=...., the following would work.
SELECT SUBSTR(image_desc, LOCATE('image=', image_desc) + 6) AS image
FROM images;
if your image description content pattern is always the same and the value youa are looking for is at the right od the = char
then you could check for the right part after the = char this way
For mysql
select SUBSTRING_INDEX(your_column_name,'=',-1)
from your_table
where your_column_name like '%image%';
for Oracle you could use
SUBSTR(youc_col, INSTR(you_col, '=') + 1)
select SUBSTR(youc_col, INSTR(you_col, '=') + 1)
from your_table
where your_column_name like '%image%';

SQL Server - How to check if a value does not exist in other rows of the same table for same column values?

Following are the two tables in SQL Server: TABLE_A and TABLE_B
I need to get the output as follows:
Get IDs from TABLE_A where Exist = 0
We would get 100, 101 & 102
Now, among 100, 101 & 102, no other rows (in the same table) with the same ID value should have Exist = 1
Hence, 100 can't be selected as it has Exist = 1 in the 2nd row.
So, only 101 & 102 remain
With the remaining ID values (101 & 102), check against the ID column in TABLE_B where 'Exist' column value should not be equal to '1' in any of the rows
In TABLE_B, 4th row has Exist = 1 for 102. So, that can't be selected
We have only 101 now. This is required output and that should be selected.
Could you let me know how to write the simplest query to achieve this please? Let me know if the question needs to be improved.
You can use exists & not exists :
with t as (
select t1.*
from t1
where exists (select 1 from t1 t11 where t11.id = t1.id and t11.exists = 0) and
not exists (select 1 from t1 t11 where t11.id = t1.id and t11.exists = 1)
)
select t.*
from t
where not exists (select 1 from t2 where t.id = t2.id and t2.exists = 1);
Try:
SELECT
ID,
SUM(CAST(Exist AS int)) AS [Exists]
FROM
TABLE_A
GROUP BY ID
HAVING SUM(CAST(Exist AS bit)) = 0
will give you the answer to the first part. You can then JOIN this to a similar query for TABLE_B. That is a "simple" way to show how this works. You can write more complex queries as that from #Yogest Sharma
Like #Peter Smith mentioned, you can use the aggregate function SUM. Note that you would need a cast since you cannot use the aggregate function on a field that has a BIT datatype
;WITH CTE AS
(
SELECT ID, SUM(CAST(Exist AS INT)) AS AggExist FROM TABLE_A GROUP BY ID
UNION
SELECT ID, SUM(CAST(Exist AS INT)) As AggExist FROM TABLE_B GROUP BY ID
)
SELECT ID, SUM(AggExist) FROM CTE GROUP BY ID
HAVING SUM(AggExist) = 0
Here is the demo

SQL - Return a default value when my search returns no results along with search criteria

I am searching with a query
--Code Format
SELECT COLA,COLB,COLC from MYTABLE where SWITCH IN (1,2,3);
If MYTABLE does not contain rows with SWITCH 1,2 or 3 I need default values returned along with the SWITCH value. How do I do it?
Below is my table format
COLA | COLB | COLC | SWITCH
------------------------------
A B C 1
a b c 2
i want a query when I search with
select * from MYTABLE where switch in (1,2,3)
That gets results like this --
COLA | COLB | COLC | SWITCH
------------------------------
A B C 1
a b c 2
NA NA NA 3
--Check to see if any row exists matching your conditions
IF NOT EXISTS (SELECT COLA,COLB,COLC from MYTABLE where SWITCH IN (1,2,3))
BEGIN
--Select your default values
END
ELSE
BEGIN
--Found rows, return them
SELECT COLA,COLB,COLC from MYTABLE where SWITCH IN (1,2,3)
END
if not exists( SELECT 1 from MYTABLE where SWITCH IN (1,2,3))
select default_value
How about:
SELECT COLA,COLB,COLC from MYTABLE where SWITCH IN (1,2,3)
union select 5555, 6666, 7777 where not exists (
SELECT COLA,COLB,COLC from MYTABLE where SWITCH IN (1,2,3)
);
5555, 6666, 7777 being the default row in case there aren't any rows matching your criteria.
Here is one way to tackle this. You need a table of the SWITCH values you want to look at. Then a simple left join makes this super easy.
select ColA
, ColB
, ColC
v.Switch
from
(
values
(1)
, (2)
, (3)
)v (Switch)
left join YourTable yt on yt.Switch = v.Switch
You can Use a Split Function And Left Join As Shown Below:
Select ISNULL(ColA,'NA') As ColA,ISNULL(ColB,'NA') As ColB,ISNULL(ColC,'NA') As ColC,ISNULL(Switch,a.splitdata)
from [dbo].[fnSplitString]('1,2,3',',') a
LEFT JOIN #MYTABLE t on a.splitdata=t.Switch
[dbo].[fnSplitString] is a Split Function with 2 arguments - Delimeter Separated String and Delimeter and Output a Table.
EDIT:
Given the new explanation, I changed the answer completely. I think I got your question now:
SELECT * FROM MYTABLE AS mt
RIGHT JOIN (SELECT 1 AS s UNION SELECT 2 AS s UNION SELECT 3 AS s) AS st
ON st.s = mt.SWITCH
You could change the SELECT 1 AS s UNION SELECT 2 AS s UNION SELECT 3 AS spart to a subquery that results in all possible values SWITCH could assume. E.g.:
SELECT DISTINCT SWITCH FROM another_table_with_all_switches
If all want is the value of switch that is not in MYTABLE, not the whole table with null values, you could try:
SELECT * FROM
(SELECT 1 AS s UNION SELECT 2 AS s UNION SELECT 3) AS st
WHERE st.s NOT IN (SELECT DISTINCT SWITCH FROM MYTABLE)

T-SQL Comma delimited value from resultset to in clause in Subquery

I have an issue where in my data I will have a record returned where a column value will look like
-- query
Select col1 from myTable where id = 23
-- result of col1
111, 104, 34, 45
I want to feed these values to an in clause. So far I have tried:
-- Query 2 -- try 1
Select * from mytableTwo
where myfield in (
SELECT col1
from myTable where id = 23)
-- Query 2 -- try 2
Select * from mytableTwo
where myfield in (
SELECT '''' +
Replace(col1, ',', ''',''') + ''''
from myTable where id = 23)
-- query 2 test -- This works and will return data, so I verify here that data exists
Select * from mytableTwo
where myfield in ('111', '104', '34', '45')
Why aren't query 2 try 1 or 2 working?
You don't want an in clause. You want to use like:
select *
from myTableTwo t2
where exists (select 1
from myTable t
where id = 23 and
', '+t.col1+', ' like '%, '+t2.myfield+', %'
);
This uses like for the comparison in the list. It uses a subquery for the value. You could also phrase this as a join by doing:
select t2.*
from myTableTwo t2 join
myTable t
on t.id = 23 and
', '+t.col1+', ' like '%, '+t2.myfield+', %';
However, this could multiply the number of rows in the output if there is more than one row with id = 23 in myTable.
If you observe closely, Query 2 -- try 1 & Query 2 -- try 2 are considered as single value.
like this :
WHERE myfield in ('111, 104, 34, 45')
which is not same as :
WHERE myfield in ('111', '104', '34', '45')
So, If you intend to filter myTable rows from MyTableTwo, you need to extract the values of fields column data to a table variable/table valued function and filter the data.
I have created a table valued function which takes comma seperated string and returns a table value.
you can refer here T-SQL : Comma separated values to table
Final code to filter the data :
DECLARE #filteredIds VARCHAR(100)
-- Get the filter data
SELECT #filteredIds = col1
FROM myTable WHERE id = 23
-- TODO : Get the script for [dbo].[GetDelimitedStringToTable]
-- from the given link and execute before this
SELECT *
FROM mytableTwo T
CROSS APPLY [dbo].[GetDelimitedStringToTable] ( #filteredIds, ',') F
WHERE T.myfield = F.Value
Please let me know If this helps you!
I suppose col is a character type, whose result would be like like '111, 104, 34, 45'. If this is your situation, it's not the best of the world (denormalized database), but you can still relate these tables by using character operators like LIKE or CHARINDEX. The only gotcha is to convert the numeric column to character -- the default conversion between character and numeric is numeric and it will cause a conversion error.
Since #Gordon, responded using LIKE, I present a solution using CHARINDEX:
SELECT *
FROM mytableTwo tb2
WHERE EXISTS (
SELECT 'x'
FROM myTable tb1
WHERE tb1.id = 23
AND CHARINDEX(CONVERT(VARCHAR(20), tb2.myfield), tb1.col1) > 0
)

is there a PRODUCT function like there is a SUM function in Oracle SQL?

I have a coworker looking for this, and I don't recall ever running into anything like that.
Is there a reasonable technique that would let you simulate it?
SELECT PRODUCT(X)
FROM
(
SELECT 3 X FROM DUAL
UNION ALL
SELECT 5 X FROM DUAL
UNION ALL
SELECT 2 X FROM DUAL
)
would yield 30
select exp(sum(ln(col)))
from table;
edit:
if col always > 0
DECLARE #a int
SET #a = 1
-- re-assign #a for each row in the result
-- as what #a was before * the value in the row
SELECT #a = #a * amount
FROM theTable
There's a way to do string concat that is similiar:
DECLARE #b varchar(max)
SET #b = ""
SELECT #b = #b + CustomerName
FROM Customers
Here's another way to do it. This is definitely the longer way to do it but it was part of a fun project.
You've got to reach back to school for this one, lol. They key to remember here is that LOG is the inverse of Exponent.
LOG10(X*Y) = LOG10(X) + LOG10(Y)
or
ln(X*Y) = ln(X) + ln(Y) (ln = natural log, or simply Log base 10)
Example
If X=5 and Y=6
X * Y = 30
ln(5) + ln(6) = 3.4
ln(30) = 3.4
e^3.4 = 30, so does 5 x 6
EXP(3.4) = 30
So above, if 5 and 6 each occupied a row in the table, we take the natural log of each value, sum up the rows, then take the exponent of the sum to get 30.
Below is the code in a SQL statement for SQL Server. Some editing is likely required to make it run on Oracle. Hopefully it's not a big difference but I suspect at least the CASE statement isn't the same on Oracle. You'll notice some extra stuff in there to test if the sign of the row is negative.
CREATE TABLE DUAL (VAL INT NOT NULL)
INSERT DUAL VALUES (3)
INSERT DUAL VALUES (5)
INSERT DUAL VALUES (2)
SELECT
CASE SUM(CASE WHEN SIGN(VAL) = -1 THEN 1 ELSE 0 END) % 2
WHEN 1 THEN -1
ELSE 1
END
* CASE
WHEN SUM(VAL) = 0 THEN 0
WHEN SUM(VAL) IS NOT NULL THEN EXP(SUM(LOG(ABS(CASE WHEN SIGN(VAL) <> 0 THEN VAL END))))
ELSE NULL
END
* CASE MIN(ABS(VAL)) WHEN 0 THEN 0 ELSE 1 END
AS PRODUCT
FROM DUAL
The accepted answer by tuinstoel is correct, of course:
select exp(sum(ln(col)))
from table;
But notice that if col is of type NUMBER, you will find tremendous performance improvement when using BINARY_DOUBLE instead. Ideally, you would have a BINARY_DOUBLE column in your table, but if that's not possible, you can still cast col to BINARY_DOUBLE. I got a 100x improvement in a simple test that I documented here, for this cast:
select exp(sum(ln(cast(col as binary_double))))
from table;
Is there a reasonable technique that would let you simulate it?
One technique could be using LISTAGG to generate product_expression string and XMLTABLE + GETXMLTYPE to evaluate it:
WITH cte AS (
SELECT grp, LISTAGG(l, '*') AS product_expression
FROM t
GROUP BY grp
)
SELECT c.*, s.val AS product_value
FROM cte c
CROSS APPLY(
SELECT *
FROM XMLTABLE('/ROWSET/ROW/*'
PASSING dbms_xmlgen.getXMLType('SELECT ' || c.product_expression || ' FROM dual')
COLUMNS val NUMBER PATH '.')
) s;
db<>fiddle demo
Output:
+------+---------------------+---------------+
| GRP | PRODUCT_EXPRESSION | PRODUCT_VALUE |
+------+---------------------+---------------+
| b | 2*6 | 12 |
| a | 3*5*7 | 105 |
+------+---------------------+---------------+
More roboust version with handling single NULL value in the group:
WITH cte AS (
SELECT grp, LISTAGG(l, '*') AS product_expression
FROM t
GROUP BY grp
)
SELECT c.*, s.val AS product_value
FROM cte c
OUTER APPLY(
SELECT *
FROM XMLTABLE('/ROWSET/ROW/*'
passing dbms_xmlgen.getXMLType('SELECT ' || c.product_expression || ' FROM dual')
COLUMNS val NUMBER PATH '.')
WHERE c.product_expression IS NOT NULL
) s;
db<>fiddle demo
*CROSS/OUTER APPLY(Oracle 12c) is used for convenience and could be replaced with nested subqueries.
This approach could be used for generating different aggregation functions.
There are many different implmentations of "SQL". When you say "does sql have" are you referring to a specific ANSI version of SQL, or a vendor specific implementation. DavidB's answer is one that works in a few different environments I have tested but depending on your environment you could write or find a function exactly like what you are asking for. Say you were using Microsoft SQL Server 2005, then a possible solution would be to write a custom aggregator in .net code named PRODUCT which would allow your original query to work exactly as you have written it.
In c# you might have to do:
SELECT EXP(SUM(LOG([col])))
FROM table;