I use Microsoft SQL Server 2016.
I have a column that is called Failover and looks like his:
$D$Failov:12345:54362:28564
$D$Failov:12345:
$D$Failov:86905:45634
I want that number so I use :
select substring(failover, 10, 5)
from dbo.f009
where failover like '$D$Failov:%'
It works fine, but if I want a second column called Account, it crashed with multiple results…
Select
account,
(Select substring(failover, 10, 5) AS "1.Result"
from dbo.f009
where Failover like '$D$Failov:%')
from
f009
where
Failover like '$D$Failov:%'
How to fix this ?
Is there a simple way to take the second number and third? I can do it with:
substring(failover, 16, 5), substring(failover, 22, 5)
etc etc but it don't want to repeat myself.
You can repeat the string operations:
select substring(failover, 11, 5) as num1,
substring(failover, 17, 5) as num2,
substring(failover, 23, 5) as num3
from dbo.f009
where failover like '$D$Failov:%';
You can also phrase this as a recursive CTE, if you have an indefinite number of values:
with t as (
select * from (values ('$D$Failov:12345:54362:28564'), ('$D$Failov:12345:')) v(failover)
),
cte as (
select failover, convert(varchar(max), NULL) as acct, convert(varchar(max), stuff(failover, 1, 10, '')) as rest, 0 as lev
from t
union all
select failover, left(rest, 5), stuff(rest, 1, 6, ''), lev + 1
from cte
where rest > ':'
)
select failover, acct, lev
from cte
where lev > 0;
Here is a db<>fiddle.
It seems that what you want can be achieved with a simple query:
Select account, substring(failover,10,5) AS "1.Result"
from dbo.f009
where Failover like '$D$Failov:%'
Related
im trying to make the query more efficient, is there a way to use an alias in order to call regexp_substr only once?
this is the sql query:
SELECT *,
(SUBSTRING(REGEXP_SUBSTR(A, '(://([a-zA-Z0-9]+):)', 1, 1, 'c'), 4, LENGTH(REGEXP_SUBSTR(A, '(://([a-zA-Z0-9]+):)', 1, 1, 'c')) - 4)) as custom
FROM table
No need for a second regexp_substr, simply use 2 argument SUBSTRING. (I.e. substring from position 4 to the end):
SELECT *,
SUBSTRING(REGEXP_SUBSTR(A, '(://([a-zA-Z0-9]+):)', 1, 1, 'c'), 4) as custom
FROM table
https://docs.snowflake.com/en/sql-reference/functions/substr.html
The below Oracle query takes a comma-separated list of values, like '3,4', and returns its individual tokens, 3 and 4, in separate rows.
Can somebody please show how to do the same in SQL Server.
SELECT REGEXP_SUBSTR('3,4','[^,]+', 1, LEVEL)
FROM DUAL
CONNECT BY REGEXP_SUBSTR('3,4', '[^,]+', 1, LEVEL) IS NOT NULL
The query would use a recursive CTE. I think this is the logic:
with c as (
select '3,4' as rest, NULL as val
union all
select stuff(rest, charindex(',', rest + ',') + 1),
left(rest, charindex(',', rest + ',') - 1)
from c
)
select col
from c;
I should note that Oracle 12c supports recursive CTEs, which I (at least) find more intuitive than connect by.
I have the below data coming from DB. I would like to get the maximum of last digits after ".". For example data looks like this, where the last digits after last "." are 160410, 6, 16 etc.
I would like to get the "11.2.0.4.160419" output
11.2.0.4.160419
11.2.0.4.6
11.2.0.4.16
11.2.0.4.10
11.2.0.4.18
11.2.0.4.2
11.2.0.4.14
11.2.0.4.4
11.2.0.4.160119
11.2.0.4.3
11.2.0.4.15
11.2.0.4.9
11.2.0.4.17
11.2.0.4.8
11.2.0.4.5
11.2.0.4.7
11.2.0.4.1
11.2.0.4.151117
11.2.0.4.13
11.2.0.4.12
11.2.0.4.20
11.2.0.4.11
11.2.0.4.19
data before the "." are not same. It has various values. Infact the actual data is like this
DATABASE PATCH FOR EXADATA (JAN 2016 - 11.2.0.4.160119) : (22309110)
DATABASE PATCH FOR EXADATA (JAN 2016 - 11.2.0.4.16) : (22309111)
.
.
In this I am interested to get max of 160119.
-- Added
Sorry I am back again. We are looking for further where we need to get the result like this
11.2.0.4.160419
Meaning, the maximum of after "." , but when displaying display everything in between the parenthesis.
Actual data
'DATABASE PATCH FOR EXADATA (NOV 2015 - 11.2.0.4.151117)
DATABASE PATCH FOR EXADATA (APR2014 - 11.2.0.4.6) : (18293775)
DATABASE PATCH FOR EXADATA (APR2015 - 11.2.0.4.16) : (20449729)
desired output
(NOV 2015 - 11.2.0.4.151117)
I have this query working
with
inputs ( target_guid, description) as (
select t.target_guid, a.description from MGMT$OH_PATCH a, mgmt$oh_installed_targets oh,MGMT$TARGET_COMPONENTS c,MGMT$TARGET_FLAT_MEMBERS d, mgmt_targets t where t.target_type = 'oracle_dbmachine' and d.member_target_type = 'host' and d.aggregate_target_guid = t.target_guid and c.target_type = 'oracle_database' and c.host_name = d.member_target_name and a.host_name = c.host_name and a.target_guid = oh.oh_target_guid and oh.inst_target_type like '%database%' and a.description is not null and a.description like '%PATCH FOR EXADATA%' group by t.target_guid, a.description order by t.target_guid
)
select target_guid, max(to_number(regexp_substr(description, '.(\d*))', 1, 1, null, 1))) as version
from inputs group by target_guid;
with the output of
5DA0496CCCD42CA1099F1AD06216F3C0 160419
ED10DD7D4C62CEAA117E7B7E97883EC2 9
I need the output as
5DA0496CCCD42CA1099F1AD06216F3C0 11.2.0.4.160419
ED10DD7D4C62CEAA117E7B7E97883EC2 11.2.0.4.9
Can you please help?
You can extract the last digits using:
select regexp_substr(col, '[0-9]+$', 1, 1)
If you don't like depending on the greediness of Oracle regular expressions (which I can appreciate), you can use:
select trim(leading '.' from regexp_substr(col, '[.][0-9]+$', 1, 1))
You can get the maximum value by converting to a numeric and taking the max:
select max(cast(regexp_substr(col, '[0-9]+$', 1, 1) as number))
To get the full column:
select t.*
from (select t.*
from t
order by cast(regexp_substr(col, '[0-9]+$', 1, 1) as number) desc
) t
where rownum = 1;
Finally, for your particular data, there is a simpler solution:
select t.*
from (select t.*
from t
order by length(col) desc, col desc
) t
where rownum = 1;
However, this assumes that all the stuff before the final '.' is the same.
If the assumptions I detailed in my Comment to your original question are correct, then something like this should work:
with
inputs ( inp_str ) as (
select 'DATABASE PATCH FOR EXADATA (JAN 2016 - 11.2.0.4.160119) : (22309110)'
from dual union all
select 'DATABASE PATCH FOR EXADATA (JAN 2016 - 11.2.0.4.16) : (22309111)' from dual
)
select max(to_number(regexp_substr(inp_str, '.(\d*)\)', 1, 1, null, 1))) as max_something
from inputs;
The select statement is really just the last two lines; the rest is for testing purposes. Replace inp_str with your actual column name, inputs with your table name, and max_something with your desired output column name.
EDIT:
Here is a solution for the OP's restated problem (see request in comments).
with
inputs ( inp_str ) as (
select 'DATABASE PATCH FOR EXADATA (JAN 2016 - 11.2.0.4.160119) : (22309110)'
from dual union all
select 'DATABASE PATCH FOR EXADATA (JAN 2016 - 11.2.0.4.16) : (22309111)' from dual
)
select regexp_substr(inp_str, '\(([^)]+)\)', 1, 1, null, 1) as token
from inputs
where to_number(regexp_substr(inp_str, '.(\d*)\)', 1, 1, null, 1)) =
( select max(to_number(regexp_substr(inp_str, '.(\d*)\)', 1, 1, null, 1)))
from inputs
)
;
Output:
TOKEN
-------------------------
JAN 2016 - 11.2.0.4.160119
1 row selected.
Maybe check out Oracle regexp_like e.g. WHERE REGEXP_LIKE(first_name, EXPRESSION)
I'm trying to select several different sums, one of them being OVER (Partition by column_also_in_select_plan).
However I cannot seem to ever be able to get the GROUP BY statement right.
Example:
Select 1, 2, 3, sum(4) over (partition by 3), sum(case when 6 = etc...)
FROM table
Where filters
GROUP BY ?
Thanks for any tips :)
It doesn't really make much sense to be doing aggregation and using window functions at the same time, so I'm not surprised you're confused. In the above example, you probably want to move the windowing to an outer query, that is:
select 1, 2, 3, sum(sum4) over(partition by 3), ...
from (
select 1, 2, 3, sum(4) as sum4
from table
where filters
group by 1, 2, 3
) x
How can I limit a result set to n distinct values of a given column(s), where the actual number of rows may be higher?
Input table:
client_id, employer_id, other_value
1, 2, abc
1, 3, defg
2, 3, dkfjh
3, 1, ldkfjkj
4, 4, dlkfjk
4, 5, 342
4, 6, dkj
5, 1, dlkfj
6, 1, 34kjf
7, 7, 34kjf
8, 6, lkjkj
8, 7, 23kj
desired output, where limit distinct=5 distinct values of client_id:
1, 2, abc
1, 3, defg
2, 3, dkfjh
3, 1, ldkfjkj
4, 4, dlkfjk
4, 5, 342
4, 6, dkj
5, 1, dlkfj
Platform this is intended for is MySQL.
You can use a subselect
select * from table where client_id in
(select distinct client_id from table order by client_id limit 5)
This is for SQL Server. I can't remember, MySQL may use a LIMIT keyword instead of TOP. That may make the query more efficient if you can get rid of the inner most subquery by using the LIMIT and DISTINCT in the same subquery. (It looks like Vinko used this method and that LIMIT is correct. I'll leave this here for the second possible answer though.)
SELECT
client_id,
employer_id,
other_value
FROM
MyTable
WHERE
client_id IN
(
SELECT TOP 5
client_id
FROM
(
SELECT DISTINCT
client_id
FROM
MyTable
) SQ
ORDER BY
client_id
)
Of course, add in your own WHERE clause and ORDER BY clause in the subquery.
Another possibility (compare performance and see which works out better) is:
SELECT
client_id,
employer_id,
other_value
FROM
MyTable T1
WHERE
T1.code IN
(
SELECT
T2.code
FROM
MyTable T2
WHERE
(SELECT COUNT(*) FROM MyTable T3 WHERE T3,code < T2.code) < 5
)
-- Using Common Table Expression in Microsoft SQL Server.
-- LIMIT function does not exist in MS SQL.
WITH CTE
AS
(SELECT DISTINCT([COLUMN_NAME])
FROM [TABLE_NAME])
SELECT TOP (5) [[COLUMN_NAME]]
FROM CTE;
This works for MS SQL if anyone is on that platform:
SET ROWCOUNT 10;
SELECT DISTINCT
column1, column2, column3,...
FROM
Table1
WHERE ...