simplifying values in column - sql

my table looks like this:
| col1 | col2 | col3 |
| xxx001xxx1 | ... | ... |
| xxx001xxx2 | ... | ... |
| xxx001xxx3 | ... | ... |
| xxx002xxx1 | ... | ... |
| xxx002xxx2 | ... | ... |
| xxx003xxx1 | ... | ... |
i want to update the table, so it will be look like this:
| col1 | col2 | col3 |
| 1 | ... | ... |
| 1 | ... | ... |
| 1 | ... | ... |
| 2 | ... | ... |
| 2 | ... | ... |
| 3 | ... | ... |
any suggestions?

You could use SUBSTRING:
SELECT CAST(SUBSTRING(col1, 4,3) AS INT) AS col1, col2, col3
FROM tab_name;
And UPDATE:
UPDATE tab_name
SET col1 = CAST(SUBSTRING(col1, 4,3) AS INT);
EDIT:
my table got 600 entries and i want no leading zeros for the smaller numbers
There wont't be leading zeros: Rextester Demo

This is pretty easy when the numbers are always in the right spot. For fun, here's how you' solve this for the following sample data:
Sample data
col1
--------------
xxx001xxx1
xxxx005xxx2
xxxxxx0010xxx3
xxx00015xxx1
xxx00007xxx2
xxx0033xxx1
Solution
-- sample data
declare #sometable table (col1 varchar(100));
insert #sometable
values ('xxx001xxx1'), ('xxxx005xxx2'), ('xxxxxx0010xxx3'),
('xxx00015xxx1'), ('xxx00007xxx2'), ('xxx0033xxx1');
-- solution
with prep as ( select col1, nbrStart = substring(col1, patindex('%[0-9][0-9]%',col1), 100)
from #sometable)
select col1,
nbr = cast(substring(nbrStart, 1, patindex('%[^0-9]%', nbrStart)-1) as int)
from prep;
Results
col1 nbr
---------------------------------- -----------
xxx001xxx1 1
xxxx005xxx2 5
xxxxxx0010xxx3 10
xxx00015xxx1 15
xxx00007xxx2 7
xxx0033xxx1 33

Related

Translate table values to text following a fixed pattern

We use software to store combinations of financial elements. Those elements are allowed in certain combinations. Exceptions of these combinations are SQL-like statements in the front-end, and are saved as numerical values in a database table like the following example:
+------+------+------+------+------+
| Col1 | Col2 | Col3 | Col4 | Col5 |
+------+------+------+------+------+
| 1 | 2 | 4 | 5 | 1 |
+------+------+------+------+------+
| -1 | 2 | 6 | 4 | 5 |
+------+------+------+------+------+
| 1 | 2 | 5 | 7 | 1 |
+------+------+------+------+------+
I would like to translate those numerical values back to a SQL-statement like the following example:
+------+-----------+------+-----------+------+-----------+------+-----------+------+-----------+
| Col1 | Col1Trans | Col2 | Col2Trans | Col3 | Col3Trans | Col4 | Col4Trans | Col5 | Col5Trans |
+------+-----------+------+-----------+------+-----------+------+-----------+------+-----------+
| 1 | ( | 2 | SELECT | 4 | CODE | 5 | LIKE | 1 | * |
+------+-----------+------+-----------+------+-----------+------+-----------+------+-----------+
| -1 | | 2 | SELECT | 6 | NUMBER | 4 | = | 5 | AND |
+------+-----------+------+-----------+------+-----------+------+-----------+------+-----------+
| 1 | ( | 2 | SELECT | 5 | TOOL | 7 | <> | 1 | * |
+------+-----------+------+-----------+------+-----------+------+-----------+------+-----------+
The numerical values differ in each column so I can only imagine the use of a lot of case...when statements which I doubt will be efficiƫnt. I don't want to create tables to hold the translation values. Are there ways to do this with arrays?
Are there any code samples to easily loop through table/columns and translate the contents of it?
You can use below code and add more case statement as per the requirement.
SELECT Col1
,CASE
WHEN Col1 = 1 THEN '('
ELSE '' END AS Col1Trans
,Col2
,CASE
WHEN Col2 = 2 THEN 'SELECT'
END AS Col2Trans
,Col3
,CASE
WHEN Col3 = 4 THEN 'CODE'
WHEN Col3 = 6 THEN 'NUMBER'
WHEN Col3 = 5 THEN 'TOOL'
END AS Col3Trans
,Col4
,CASE
WHEN Col4 = 5 THEN 'LIKE'
WHEN Col4 = 4 THEN '='
WHEN Col4 = 7 THEN '<>'
END AS Col4Trans
,Col5
,CASE
WHEN Col5 = 1 THEN '*'
WHEN Col5 = 5 THEN 'AND'
END AS Col5Trans
The best way to avoid so many case when and decode and etc is to use with as clause as following:
With col1trans (value, translation) as
(Select 1, '(' from dual union all
Select -1, null from dual),
Col2trans (value, translation) as
(Select 2, 'SELECT' from dual)
..
... till col5trans
Select m.col1, t1.translation as col1trans,
.... till m.col5, t5.translation
From your_table m join col1trans t1 m.col1=t1.value
join col2trans t2 m.col2=t2.value
... till col5trans
Cheers!!

Over Partition to find duplicates and remove them based on criteria SQL

I hope everyone is doing well. I have a dilemma that i can not quite figure out.
I am trying to find a unique value for a field that is not a duplicate.
For example:
Table 1
|Col1 | Col2| Col3 |
| 123 | A | 1 |
| 123 | A | 2 |
| 12 | B | 1 |
| 12 | B | 2 |
| 12 | C | 3 |
| 12 | D | 4 |
| 1 | A | 1 |
| 2 | D | 1 |
| 3 | D | 1 |
Col 1 is the field that would have the duplicate values. Col2 would be the owner of the value in Col 1. Col 3 uses the row number() Over Partition syntax to get the numbers in ascending order.
The goal i am trying to accomplish is to remove the value in col 1 if it is not truly unique when looking at col2.
Example:
Col1 has the value 123, Col2 has the value A. Although there are two instances of 123 being owned by A, i can determine that it is indeed unique.
Now look at Col1 that has the value 12 with values in Col2 of B,C,D.
Value 12 is associated with three different owners thus eliminating 12 from our result list.
So in the end i would like to see a result table such as this :
|Col1 | Col2|
| 123 | A |
| 1 | A |
| 2 | D |
| 3 | D |
To summarize, i would like to first use the partition numbers to identify if the value in col1 is repeated. From there i want to verify that the values in col 2 are the same. If so the value in col 1 and col 2 remains as one single entry. However if the values in col 2 do not match, all records for the col1 value are removed.
I will provide the syntax code for my query if needed.
Update**
I failed to mention that table 1 is the result of inner joining two tables.
So Col1 comes from table a and Col2 comes from table b.
The values in table a for col2 are hard to interpret so i had to make sense of them and assigned it proper name values.
The join query i used to combine the two are:
Select a.Col1, B.Col2 FROM Table a INNER JOIN Table b on a.Colx = b.Colx
Update**
Table a:
|Col1 | Colx| Col3 |
| 123 | SMS | 1 |
| 123 | S9W | 2 |
| 12 | NAV | 1 |
| 12 | NFR | 2 |
| 12 | ABC | 3 |
| 12 | DEF | 4 |
| 1 | SMS | 1 |
| 2 | DEF | 1 |
| 3 | DES | 1 |
Table b:
|Colx | Col2|
| SMS | A |
| S9W | A |
| DEF | D |
| DES | D |
| NAV | B |
| NFR | B |
| ABC | C |
Above are sample data for both tables that get joined in order to create the first table displayed in this body.
Thank you all so much!
NOT EXISTS operator can be used to do this task:
SELECT distinct Col1 , Col2
FROM table t
WHERE NOT EXISTS(
SELECT 1 FROM table t1
WHERE t.col1=t1.col1 AND t.col2 <> t1.col2
)
If I understand correctly, you want:
select col1, min(col2)
from t
group by col1
where min(col2) <> max(col2);
I think the third column is confusing you. It doesn't seem to play any role in the logic you want.

How to combine multiple columns into one column in SQL?

Based on the Google Form input I have the following data collected from the user
+-------+--------+--------+--------+
| Name | Col1 | Col2 | Col3 |
+-------+--------+--------+--------+
| name1 | | | 1 |
| name2 | 3 | | |
| name3 | | 2 | |
+-------+--------+--------+--------+
which only one of the Col1, Col2 or Col3 will contain value
What I want is to created a view like this
+-------+--------+
| Name | Col |
+-------+--------+
| name1 | 1 |
| name3 | 2 |
| name2 | 3 |
+-------+--------+
The SQL command should not only merge Col1, Col2 and Col3 but also sort the new Col based on it value.
Thanks in advance
You can use coalesce():
select name, coalesce(col1, col2, col3) as col
from t
order by col;
The simplest method below (I'-'I's answer is good but a little overcomplicated) given the particularities of your data
=sort(arrayformula({H1:H6, I1:I6 + J1:J6 + K1:K6}), 2, true)
Sheets doesn't support full sql.
=ARRAYFORMULA(SORT({A2:A4,MMULT(--B2:D4,TRANSPOSE(B2:D2^0))},2,1))

clear string in a column for specific rows

i got a table which looks like this:
| col1 | ... | colx |
---------------------
| 1 | ... | dfd |
| 1 | ... | ajd |
| 1 | ... | aad |
| 2 | ... | azd |
| 2 | ... | iod |
| 3 | ... | asd |
| 3 | ... | aod |
| 3 | ... | wsd |
| 3 | ... | asi |
i want to update the table (or create a new table), so it looks like this:
| col1 | ... | colx |
---------------------
| 1 | ... | dfd |
| | ... | ajd |
| | ... | aad |
| 2 | ... | azd |
| | ... | iod |
| 3 | ... | asd |
| | ... | aod |
| | ... | wsd |
| | ... | asi |
any suggestions?
1.First add a new identity column to your table so we can order and update duplicate duplicate values to null:
alter table yourtable
add newcol int identity
2. If you want to update duplicate values in col1 to null then:
update yourtable
set col1 = null
where newcol not in (select min(newcol) from yourtable group by col1)
3.See your result:
select
*
from
yourtable
order by
newcol asc
You can not drop the identity column that was created but then you will loose your order..
If you don't want to update anything and just need a query
1.All you need is the following query AFTER you have created a new identity column on your table
select
*
from
yourtable
where
newcol in (select min(newcol) from yourtable group by col1)
Example
Select col1 = case when RN=1 then concat('',col1) else '' end
,other
,colx
From (
Select *
,RN = Row_Number() over (Partition By col1 order by colx)
From YourTable
) A
Order by A.Col1,RN
Returns
Something like this?
DECLARE #MyTable TABLE
(
COL1 int,
COLX nvarchar(50)
)
INSERT INTO #MyTable(COL1,COLX)
VALUES
( 1 ,'dfd'),
( 1 ,'ajd'),
( 1 ,'aad'),
( 2 ,'azd'),
( 2 ,'iod'),
( 3 ,'asd'),
( 3 ,'aod'),
( 3 ,'wsd'),
( 3 ,'asi')
select ISNULL(newcol,'')as col1,COLX from (
Select COLX,cast(Case when rn = 1 then COL1 else null end as nvarchar(50))
as NewCOL from (
Select * ,Row_number() over(Partition by col1 order by col1 ) as rn from
#MyTable
)x
)y
Result:

TSQL select the from two rows that has higher priority and is not null

I try to consolidate two rows of the same table whereas each row has a priority.
The value of interest is the value having priority 1 if it is not NULL; otherwise the value with priority 0.
An example data source could be:
| Id | GroupId | Priority | Col1 | Col2 | Col3 | ... | Coln |
-----------------------------------------------------------------
| 1 | 1 | 0 | NULL | 4711 | 3.41 | ... | f00 |
| 2 | 1 | 1 | NULL | NULL | 2.83 | ... | bar |
| 3 | 2 | 0 | NULL | 4711 | 3.41 | ... | f00 |
| 4 | 2 | 1 | 23 | NULL | 2.83 | ... | NULL |
and I want to have:
| GroupId | Col1 | Col2 | Col3 | ... | Coln |
-------------------------------------------------
| 1 | NULL | 4711 | 2.83 | ... | bar |
| 2 | 23 | 4711 | 2.83 | ... | f00 |
Is there a generic way in TSQL without the need to check each column explicitly?
SELECT
t1.GroupId,
ISNULL(t2.Col1, t1.Col1) as Col1,
ISNULL(t2.Col2, t1.Col2) as Col2,
ISNULL(t2.Col3, t1.Col3) as Col3,
...
ISNULL(t2.Coln, t1.Coln) as Coln
FROM mytable t1
JOIN mytable t2 ON t1.GroupId = t2.GroupId
WHERE
t1.Priority = 0 AND
t2.Priority = 1
Regards
I'll elaborate the ROW_NUMBER() solution that #KM suggested since IMO it's the best solution for this. (In CTE form for easier readability)
WITH cte AS (
SELECT
t1.GroupId,
t1.Col1,
t1.Col2,
ROW_NUMBER() OVER(PARTITION BY t1.GroupId ORDER BY ISNULL(GroupId ,-1) ) AS [row_id]
FROM
mytable t1
)
SELECT
*
FROM
cte
WHERE
row_id = 1
That will give you the row with the highest priority (according to your rules) for each GroupId in mytable.
ROW_NUMBER and RANK are two of my favorite TSQL tricks. http://msdn.microsoft.com/en-us/library/ms186734.aspx
edit: Another favorite of mine is PIVOT/UNPIVOT which you can use to transpose rows/columns which is another way of going about this type of problem. http://msdn.microsoft.com/en-us/library/ms177410.aspx
I think this would do what you are asking for without using isnull for every column
select
*
from
mytable t1
where
priority=(select max(priority) from mytable where groupid=t1.groupid group by groupid)