How to get certain word from a column value - sql

Column A
/Site/Test1/mysite/Do?id=90
/Site/Test2/mysite/Done?id=10
/NewSite/Site/Test3/mysite/Do?id=90
/Site/Test3/mysite/Done?id=1901
What I am trying to do is get the Test# from each row as well as the # after the =.
I tried the following:
Select
SUBSTRING(Column A, CHARINDEX('/', Column A, 1) + 7, LEN(Column A)),
SUBSTRING(Column A, CHARINDEX('=', Column A, 1) + 1, LEN(Column A)),
Column A
from
Table1
I am able to get the # after the = but how can I get the Test# from each row.
UPDATE: Test# is an example, it can be anything in there. What is for certain is Site and NewSite.
UPDATE #2:
Updated Table:
Column A
/Site/My%20Web%20Site/mysite/Do?id=90
/Site/Test%20It%20Out/mysite/Do?id=101
/Site/Test1/dummy/Done?id=1000
/NewSite/Site/No%20Way/thesite/Do?id=909
Result:
Col1 Col2
My%20Web%20Site 90
Test%20It%20Out 101
Test1 1000
No%20Way 909

select
Col1 = substring(a
, charindex('/Site/', a)+6
, charindex('/', a,(charindex('/Site/', a)+6))-(charindex('/Site/', a)+6)
)
, Col2 = substring(a
, charindex('=', a, 1) + 1
, len(a))
from t
rextester demo: http://rextester.com/DEBB37305
returns:
+-----------------+------+
| Col1 | Col2 |
+-----------------+------+
| My%20Web%20Site | 90 |
| Test%20It%20Out | 101 |
| Test1 | 1000 |
| No%20Way | 909 |
+-----------------+------+

This should work:
select SUBSTRING(col,CHARINDEX('Test',col),5)
To test it with one example:
select SUBSTRING('/Site/Test1/mysite/Do?id=90',CHARINDEX('Test','/Site/Test1/mysite/Do?id=90'),5)

Related

Why and How do ORDER BY CASE Queries Work in SQL Server?

Let's look at the following table:
| col1 | col2 |
| -------- | -------------- |
| 1 | NULL |
| 23 | c |
| 73 | NULL |
| 43 | a |
| 3 | d |
Suppose you wanted to sort it like this:
| col1 | col2 |
| -------- | -------------- |
| 1 | NULL |
| 73 | NULL |
| 43 | a |
| 23 | c |
| 3 | d |
With the following code this would be almost trivial:
SELECT *
FROM dbo.table1
ORDER BY col2;
However, to sort it in the following, non-standard way isn't that easy:
| col1 | col2 |
| -------- | -------------- |
| 43 | a |
| 23 | c |
| 3 | d |
| 1 | NULL |
| 73 | NULL |
I made it with the following code
SELECT *
FROM dbo.table1
ORDER BY CASE WHEN col2 IS NULL THEN 1 ELSE 0 END, col2;
Can you explain to me 1) why and 2) how this query works? What bugs me is that the CASE-statement returns either 1 or 0 which means that either ORDER BY 1, col2 or ORDER BY 0, col2 will be executed. But the following code gives me an error:
SELECT *
FROM dbo.table1
ORDER BY 0, col2;
Yet, the overall statement works. Why?
How does this work?
ORDER BY (CASE WHEN col2 IS NULL THEN 1 ELSE 0 END),
col2;
Well, it works exactly as the code specifies. The first key for the ORDER BY takes on the values of 1 and 0 based on col2. The 1 is only when the value is NULL. Because 1 > 0, these are sorted after the non-NULL values. So, all non-NULL values are first and then all NULL values.
How are the non-NULL values sorted? That is where the second key comes in. They are ordered by col2.
Starting with this sample data:
--==== Sample Data
DECLARE #t TABLE (col1 INT, col2 VARCHAR(10))
INSERT #t(col1,col2) VALUES (1,NULL),(23,'c'),(73,NULL),(43,'a'),(3 ,'d');
Now note these three queries that do the exact same thing.
--==== QUERY1: Note the derived query
SELECT t.col1, t.col2
FROM
(
SELECT t.col1, t.col2, SortBy = CASE WHEN col2 IS NULL THEN 1 ELSE 0 END
FROM #t AS t
) AS t
ORDER BY t.SortBy;
--==== QUERY2: This does the same thing but with less code
SELECT t.col1, t.col2, SortBy = CASE WHEN col2 IS NULL THEN 1 ELSE 0 END
FROM #t AS t
ORDER BY SortBy;
--==== QUERY3: This is QUERY2 simplified
SELECT t.col1, t.col2
FROM #t AS t
ORDER BY CASE WHEN col2 IS NULL THEN 1 ELSE 0 END;
Note that you can simplify your CASE statements like so:
--==== Simplified Case statemnt examples
SELECT t.col1, t.col2
FROM #t AS t
ORDER BY CASE col2 WHEN NULL THEN 1 ELSE 0 END;
SELECT t.col1, t.col2
FROM #t AS t
ORDER BY IIF(col2 IS NULL,1,0);
Try this:
DECLARE #Table TABLE (col1 int, col2 char(1))
INSERT INTO #Table
VALUES
( 1 , NULL)
, ( 23, 'c' )
, ( 73, NULL)
, ( 43, 'a' )
, ( 3 , 'd' )
;
SELECT *
FROM #Table
ORDER BY ISNULL(col2, CHAR(255))
Common table expressions can be a big help both as a way of clarifying an issue as well as solving it. If you move the CASE clause up into the CTE and then use it to sort, this answers both why and how it works.
With Qry1 (
SELECT col1,
col2,
CASE WHEN col2 IS NULL THEN 1 ELSE 0 END As SortKey
FROM dbo.table1
)
SELECT *
FROM Qry1
ORDER BY SortKey, col2;
This is a description for oracle database SQL's ORDER BY:
ORDER [ SIBLINGS ] BY
{ expr | position | c_alias }
[ ASC | DESC ]
[ NULLS FIRST | NULLS LAST ]
[, { expr | position | c_alias }
[ ASC | DESC ]
[ NULLS FIRST | NULLS LAST ]
]...
We can see that position and expr were depicted as separate paths in the diagram. From the fact, we can conclude that the 0 and 1 are not categorized as position because the CASE expression is not position even though the expression would be evaluated to a number, which is can be viewed as position value.
I think this view can be applied to T-SQL too.

SQL: select max(value) when change columns in table

Sorry if the title is confusing. I have a problem when Select from 2 table. I have 2 table like that.
Table 1: contains the column names of Table 2
+ Pkey | name1 | name2 +
+----------------------+
| 1 | a | b |
+----------------------+
| 2 | c | b |
Table 2: contains values
+ Pkey | a | b | c +
+----------------------+------+
| 1 | 10 | 2 | 7 |
+----------------------+------+
| 2 | 12 | 4 | 8 |
+----------------------+------+
| 3 | 8 | 2 | 4 |
+----------------------+------+
| 4 | 7 | 1 | 3 |
I want to get the max(value) from the table 2 and add when select table 1
Example: With first row of table 1 contains 2 values : a and b. From these two values, we refer to table 2 to calculated column a - column b is [8,8,6,6]. After getting the max value of this column is 8 and add when query table 1. Keep going with the next rows
Desired table:
+ Pkey | name1 | name2 | Desired column |
+----------------------+-------------------+
| 1 | a | b | 8 |
+----------------------+-------------------+
| 2 | c | b | 5 |
I have more than 10000 rows in table 1. I used function and It can not use dynamic in Function
One possible approach is to generate dynamic SQL:
-- Tables
CREATE TABLE #Table1 (
Pkey int,
name1 varchar(1),
name2 varchar(1)
)
INSERT INTO #Table1 (Pkey, name1, name2)
VALUES
(1, 'a', 'b'),
(2, 'c', 'b')
CREATE TABLE #Table2 (
Pkey int,
a int,
b int,
c int
)
INSERT INTO #Table2 (Pkey, a,b, c)
VALUES
(1, 10, 2, 7),
(2, 12, 4, 8),
(3, 8, 2, 4),
(4, 7, 1, 3)
-- Statement
DECLARE #stm nvarchar(max)
SET #stm = N''
SELECT #stm = #stm +
N'UNION ALL
SELECT
' + STR(Pkey) + ' AS Pkey,
''' + name1 + ''' AS name1,
''' + name2 + ''' AS name2, ' +
'PkeyMax = (SELECT MAX(' + name1 + ' - ' + name2 + ') FROM #Table2) '
FROM #Table1
SELECT #stm = STUFF(#stm, 1, 10, '')
-- Execution
EXEC (#stm)
Output:
Pkey name1 name2 PkeyMax
1 a b 8
2 c b 5
This gets the results you want, since there are few fields, makes sense to use CASE to get the ones you want (in order to avoid building dynamic SQL)
SELECT pkey,name1,name2,max(dif) FROM
(SELECT t1.pkey, t1.name1, t1.name2,
case when t1.name1 ='a' then t2.a
when t1.name1 ='b' then t2.b
when t1.name1 ='c' then t2.c
end
-
case when t1.name2 ='a' then t2.a
when t1.name2 ='b' then t2.b
when t1.name2 ='c' then t2.c
end dif
FROM Table1 t1 , Table2 t2) IQ
GROUP BY IQ.pkey, IQ.name1, IQ.name2

Sybase, SQL: Adding a counter to duplicate values

I try to handle the following case. I have a list of entries in the db:
Col 1 | Col 2|
------|------|
aaaa | x |
aaaa | x |
bbbb | y |
cccc | z |
cccc | z |
The goal is to identify the duplicates in Col 1 and add a number to each line and for the duplicates the number should incremented so that we get also unique entries. After each new entry the counter should start from 1 again.
Col 1 | Col 2 |
--------|-------|
aaaa-1 | x |
aaaa-2 | x |
bbbb-1 | y |
cccc-1 | z |
cccc-2 | z |
Do you have any idea how to manage this?
Best regards,
Dirk
Hi Dirk,
WITH cte
AS (SELECT Col1,Col2,ROW_NUMBER() OVER (PARTITION BY Col1,Col2
ORDER BY ( SELECT 0)) RN
FROM tableName)
select Col1+'-'+convert(varchar,rn) as Col1,Col2 FROM cte
Thanks :)
I would try this. I hope that solves your issue.
SELECT COL1 + ' - ' + ROW_NUMBER() OVER(PARTITION BY COL1 ORDER BY COL1) as COL_A
, COL2 AS COL_B
FROM TABLE
Depending on the DBMS you are working with, you might have to CAST ROW_NUMBER(). I tried that on Oracle 11.2 and it worked properly:
SELECT COL1 || ' - ' || ROW_NUMBER() OVER(PARTITION BY COL1 ORDER BY COL1) AS COL_A
, COL2 AS COL_B
FROM TABLENAME

SQL splitting a column into 3 different columns with multiple seperators

I have the column below which contains data as shown
|DeliveryComment |
|-------------------------|
|[1 * B018] |
|GARAGE |
|BACK GARDEN. [124 * B002]|
|[1 * B018] |
| |
|[124 * B002] |
|[1 * B018] |
| |
|[124 * B002] |
I'd like to split this data into three columns displayed as below.
|ColA |ColB|ColC|
|-----------|----|----|
| |1 |B018|
|GARAGE | | |
|BACK GARDEN|124 |B002|
| |1 |B018|
| | | |
| |124 |B002|
| |1 |B018|
| | | |
| |124 |B002|
The data that should end up in column A can be variable up to 11 characters.
The data that should end up in column B can be a variable numeric value up to 3 characters.
The data that should end up in column C can be variable up to 4 characters.
There will always be [] around the numbers and there will always be a * in between them.
Create and populate sample table (Please save us this step in your future questions)
DECLARE #t AS TABLE
(
col varchar(50)
)
INSERT INTO #T VALUES
('[1 * B018]'),
('GARAGE'),
('BACK GARDEN. [124 * B002]'),
('[1 * B018]'),
(''),
('[124 * B002]'),
('[1 * B018]'),
(''),
('[124 * B002]')
The query:
SELECT CASE WHEN charindex('[', col) > 0 THEN
LEFT(col, charindex('[', col)-1)
ELSE
col
END AS ColA,
CASE WHEN charindex('[', col) = 0 THEN
''
ELSE
SUBSTRING(col, charindex('[', col) +1 ,charindex('*', col) - charindex('[', col) - 1)
END AS ColB,
CASE WHEN charindex('[', col) = 0 THEN
''
ELSE
SUBSTRING(col, charindex('*', col) +1 ,charindex(']', col) - charindex('*', col) - 1)
END AS ColC
FROM #T
Results:
ColA ColB ColC
1 B018
GARAGE
BACK GARDEN. 124 B002
1 B018
124 B002
1 B018
124 B002
This solution uses CROSS APPLY to make the CHARINDEX easier to manage.
SELECT
LEFT(SUBSTRING(col,1,CASE WHEN a= 0 THEN LEN(col) ELSE a-1 END),11) AS [ColA]
,REPLACE(SUBSTRING(col,a+1,b-a),'*','') AS [ColB]
,REPLACE(SUBSTRING(col,b+1,c-b),']','') AS [ColC]
FROM
#t
CROSS APPLY( SELECT CHARINDEX('[',Col,0)A
,CHARINDEX('*',Col,0)B
,CHARINDEX(']',Col,0)C
) Z
Note: the examples you have so far -including this one - currently have leading and trailing spaces that will need trimming out with RTRIM & LTRIM. But right now they would cloud the code.

SQL: Pick highest and lowest value (int) from one row

I am looking for a way to pick the highest and lowest value (integer) from a single row in table. There are 4 columns that i need to compare together and get highest and lowest number there is.
The table looks something like this...
id | name | col_to_compare1 | col_to_compare2 | col_to_compare3 | col_to_compare4
1 | John | 5 | 5 | 2 | 1
2 | Peter | 3 | 2 | 4 | 1
3 | Josh | 3 | 5 | 1 | 3
Can you help me, please? Thanks!
You can do this using CROSS APPLY and the VALUES clause. Use VALUES to group all your compared columns and then select the max.
SELECT
MAX(d.data1) as MaxOfColumns
,MIN(d.data1) as MinOfColumns
,a.id
,a.name
FROM YOURTABLE as a
CROSS APPLY (
VALUES(a.col_to_compare1)
,(a.col_to_compare2)
,(a. col_to_compare3)
,(a.col_to_compare4)
,(a. col_to_compare5)
) as d(data1) --Name the Column
GROUP BY a.id
,a.name
Assuming you are looking for min/max per row
Declare #YourTable table (id int,name varchar(50),col_to_compare1 int,col_to_compare2 int,col_to_compare3 int,col_to_compare4 int)
Insert Into #YourTable values
(1,'John',5,5,2,1),
(2,'Peter',3,2,4,1),
(3,'Josh',3,5,1,3)
Select A.ID
,A.Name
,MinVal = min(B.N)
,MaxVal = max(B.N)
From #YourTable A
Cross Apply (Select N From (values(a.col_to_compare1),(a.col_to_compare2),(a.col_to_compare3),(a.col_to_compare4)) N(N) ) B
Group By A.ID,A.Name
Returns
ID Name MinVal MaxVal
1 John 1 5
3 Josh 1 5
2 Peter 1 4
These solutions keep the current rows and add additional columns of min/max.
select *
from t cross apply
(select min(col) as min_col
,max(col) as max_col
from (
values
(t.col_to_compare1)
,(t.col_to_compare2)
,(t.col_to_compare3)
,(t.col_to_compare4)
) c(col)
) c
OR
select *
,cast ('' as xml).value ('min ((sql:column("t.col_to_compare1"),sql:column("t.col_to_compare2"),sql:column("t.col_to_compare3"),sql:column("t.col_to_compare4")))','int') as min_col
,cast ('' as xml).value ('max ((sql:column("t.col_to_compare1"),sql:column("t.col_to_compare2"),sql:column("t.col_to_compare3"),sql:column("t.col_to_compare4")))','int') as max_col
from t
+----+-------+-----------------+-----------------+-----------------+-----------------+---------+---------+
| id | name | col_to_compare1 | col_to_compare2 | col_to_compare3 | col_to_compare4 | min_col | max_col |
+----+-------+-----------------+-----------------+-----------------+-----------------+---------+---------+
| 1 | John | 5 | 5 | 2 | 1 | 1 | 5 |
+----+-------+-----------------+-----------------+-----------------+-----------------+---------+---------+
| 2 | Peter | 3 | 2 | 4 | 1 | 1 | 4 |
+----+-------+-----------------+-----------------+-----------------+-----------------+---------+---------+
| 3 | Josh | 3 | 5 | 1 | 3 | 1 | 5 |
+----+-------+-----------------+-----------------+-----------------+-----------------+---------+---------+
A way to do this is to "break" apart the data
declare #table table (id int, name varchar(10), col1 int, col2 int, col3 int, col4 int)
insert into #table values (1 , 'John' , 5 , 5 , 2 , 1)
insert into #table values (2 , 'Peter' , 3 , 2 , 4 , 1)
insert into #table values (3 , 'Josh' , 3 , 5 , 1 , 3)
;with stretch as
(
select id, col1 as col from #table
union all
select id, col2 as col from #table
union all
select id, col3 as col from #table
union all
select id, col4 as col from #table
)
select
t.id,
t.name,
agg.MinCol,
agg.MaxCol
from #table t
inner join
(
select
id, min(col) as MinCol, max(col) as MaxCol
from stretch
group by id
) agg
on t.id = agg.id
Seems simple enough
SELECT min(col1), max(col1), min(col2), max(col2), min(col3), max(col3), min(col4), max(col4) FROM table
Gives you the Min and Max for each column.
Following OP's comment, I believe he may be looking for a min/max grouped by the person being queried against.
So that would be:
SELECT name, min(col1), max(col1), min(col2), max(col2), min(col3), max(col3), min(col4), max(col4) FROM table GROUP BY name