Incorrect syntax near "case" - sql-server

I have one table having data like this:
ID | Fill
---------------
1 | ####
2 | ####Y
3 | ####Y245
I want to insert the above data into another table and expecting the result table to be:
ID | Fill
----------------
1 | (Space)
2 | Y
3 | Y245
That is, when i find ####, it should be replace by space (4 space char as it has 4#)
Here is how I'm trying to do this:
insert into table1
(
id
,case
when contains(substring([fill],1,4),'####') then ' '+substring([fill],5,100)
else [fill]
end
)
select
id
,convert(char(100),[col1]+[col2]+[col3]+[col4])
from
table2
However, its showing syntax error near "case". What am I doing wrong? how can i achieve the desired result?

Just use replace()
insert into destination_table (col1)
select replace(col1, '#', ' ' ) from source_table
If # occurs, it will be replaced. If not, then the original string is used.

The case is in the field list part of the INSERT statement and is therefore not valid.
You could just use a simple replace to achieve this
INSERT INTO table1 (id, fill)
select id, replace(fill, '####', ' ') from table2

Related

Extraction queries with variable last part of the search term

I have a problem with an extraction query.
I want to extract all records that begin with exactly one name.
The problem:
Not always the end of the name is this extension;
When they are present, they have no fixed length.
Example:
TabNames
id | Name
1 | Mike
2 | Mike Nell-1
3 | Mike-2
4 | Robert-1
5 | Mike Rio-NN
6 | Mike-Orio-2
.....
Name searched for: 'Mike'
Desired outcome:
Mike, Mike-2
If interested, I use SQL Server.
How can I do?
You can do this with FOR XML. You will have update the Table Names, Columns Names and Where Statement in both select statements. This is a variation of this Concatenation Script.
SELECT DISTINCT
SUBSTRING(
(
SELECT ', '+ T1.Name AS [text()]
FROM dbo.TabNames T1
WHERE T1.Name LIKE 'Mike%'
ORDER BY T1.Name
FOR XML PATH ('')
), 3, 8000) AS Names
FROM
dbo.TabNames T2
WHERE
T2.Name LIKE 'Mike%'

TSQL - View with cross apply and pivot

this is my base table:
docID | rowNumber | Column1 | Column2 | Column3
I use cross apply and pivot to transform the records in Column1 to actual columns and use the values in column2 and column3 as records for the new columns. In my fiddle you can see base and transformed select statement.
I have columns like Plant and Color which are numbered, e.g. Plant1, Plant2, Plant3, Color1, Color2 etc.
For each plant that exists in all plant columns I want to create a new row with a comma separated list of colors in one single column.
What I want to achieve is also in below screenshot:
This should become a view to use in Excel. How do I need to modify the view to get to the desired result?
Additional question: The Length-column is numeric. Is there any way to switch the decimal separator from within Excel as a user and apply it to this or all numeric column(s) so that it will be recognized by Excel as a number?
I used to have an old php web query where I would pass the separator from a dropdown cell in Excel as a parameter.
Thank you.
First off, man the way your data is stored is a mess. I would recommend reading up on good data structures and fixing yours if you can. Here's a TSQL query that gets you the data in the correct format.
WITH CTE_no_nums
AS
(
SELECT docID,
CASE
WHEN PATINDEX('%[0-9]%',column1) > 0
THEN SUBSTRING(column1,0,PATINDEX('%[0-9]%',column1))
ELSE column1
END AS cols,
COALESCE(column2,column3) AS vals
FROM miscValues
WHERE column2 IS NOT NULL
OR column3 IS NOT NULL
),
CTE_Pivot
AS
(
SELECT docID,partNumber,prio,[length],material
FROM CTE_no_nums
PIVOT
(
MAX(vals) FOR cols IN (partNumber,prio,[length],material)
) pvt
)
SELECT A.docId + ' # ' + B.vals AS [DocID # Plant],
A.docID,
A.partNumber,
A.prio,
B.vals AS Plant,
A.partNumber + '#' + A.material + '#' + A.[length] AS Identification,
A.[length],
SUBSTRING(CA.colors,0,LEN(CA.colors)) colors --substring removes last comma
FROM CTE_Pivot A
INNER JOIN CTE_no_nums B
ON A.docID = B.docID
AND B.cols = 'Plant'
CROSS APPLY ( SELECT vals + ','
FROM CTE_no_nums C
WHERE cols = 'Color'
AND C.docID = A.docID
FOR XML PATH('')
) CA(colors)
Results:
DocID # Plant docID partNumber prio Plant Identification length colors
---------------- ------ ---------- ---- ---------- ------------------ ------- -------------------------
D0001 # PlantB D0001 X001 1 PlantB X001#MA123#10.87 10.87 white,black,blue
D0001 # PlantC D0001 X001 1 PlantC X001#MA123#10.87 10.87 white,black,blue
D0002 # PlantA D0002 X002 2 PlantA X002#MA456#16.43 16.43 black,yellow
D0002 # PlantC D0002 X002 2 PlantC X002#MA456#16.43 16.43 black,yellow
D0002 # PlantD D0002 X002 2 PlantD X002#MA456#16.43 16.43 black,yellow

TSQL stuff for xml path and sub query

I've to replace csv datas in column by correspondant id always in csv format
I've a problem with this query :
select t0.code , t0.categories, t0.departement, (
SELECT Stuff((
SELECT N', ' + CONVERT(varchar, id_categorie) FROM tcategories t1 WHERE t0.departement = t1.departement COLLATE French_CI_AI and categorie IN (t0.tcategories)
FOR XML PATH(''),TYPE).value('text()[1]','varchar(max)'),1,1,N'')) as id_colonne
FROM #codes_reductions t0 where categories is not null
Here is the result :
code | categories | departement | id_colonne
AIRSTREAM | 'A','B','BA' | JMQ | NULL
If I replace 'and categorie IN (t0.tcategories)' by and categorie IN ('A','B','BA') the query works good
Here is the result :
code | categories | departement | id_colonne
AIRSTREAM | 'A','B','BA' | JMQ | 128, 129, 260
I tryed to use COLLATE French_CI_AI on my column, but without success. Any idea ?
... categorie IN (t0.tcategories) ....
The cause of your problem is that categorie column stores those values ('A','B','BA') as a single value not as an array / list / table of values. So, SQL Server compares two strings thus s1 IN (s2) which is equivalent to s1 = s2 => A IN ('A','B','BA') <=> A = 'A','B','BA'.
Example (note: double single quotes ('') are used to define an empty string while four single quotes ('''') are used to define a string with a single quote: SELECT '''' --> '):
DECLARE #categories VARCHAR(1000);
SET #categories = '''A'',''B'',''BA'''
SELECT #categories AS ColA, CASE WHEN 'A' IN (#categories) THEN 'TRUE' ELSE 'FALSE' END AS Col2
/*
ColA Col2
------------ -----
'A','B','BA' FALSE
*/
The solution on short term is to use one of following conditions:
C#1 (if categorie contains single quotes): ... t0.tcategories LIKE '%' + categorie + '%' ....
C#2 (when categorie doesn't contains single quotes): ... t0.tcategories LIKE '%''' + categorie + '''%' ....
Example:
DECLARE #categories VARCHAR(1000);
SET #categories = '''A'',''B'',''BA'''
SELECT #categories AS ColA, CASE WHEN #categories LIKE '%''A''%' THEN 'TRUE' ELSE 'FALSE' END AS Col2
/*
ColA Col2
------------ -----
'A','B','BA' TRUE
*/
Second note: this works when every separate value from t0.tcategories column doesn't includes single quote(s) (example: 'B'A' / 'B''A' ).
On medium/long term, you should store separately every single value from tReduction.tCategories column using another table :
CREATE TABLE dbo.ReductionCategory (
... pk ...,
ReductionCode INT NOT NULL REFERENCES dbo.tReduction(ReductionCode), -- FK
CategoryCode INT NOT NULL REFERENCES dbo.tCategories(CategoryCode) -- FK
)
Thus, condition becomes
... categorie /*CategoryCode*/
IN (
SELECT rc.CategoryCode FROM dbo.ReductionCategory rc
WHERE rc.ReductionCode = t0.ReductionCode
) ....

How to concatenate the cells in a row?

There are many questions how to concatenate multiple rows into a varchar, but can you concatenate all the cells in a row into a varchar?
Example : A table with 3 columns
| Id | FirstName | LastName |
| 1 | John | Doe |
| 2 | Erik | Foo |
return the following
"1, John, Doe"
"2, Erik, Foo"
You know which table you are working on.
Note 1 : Assume that you don't know the name of the columns when you write your query.
Note 2 : I would like to avoid dynamic SQL (if possible)
Only thing I can think of is setting nocount to on outputting results to text instead of a grid using these parameters. That can be done without knowing amount of columns and avoiding Dynamic SQL.
SET NOCOUNT ON;
;WITH Test (Id, FirstName, LastName)
AS (
SELECT 1, 'John', 'Doe'
UNION ALL
SELECT 2, 'Erik', 'Foo'
)
SELECT *
FROM Test
Will return you this:
1,John,Doe
2,Erik,Foo
Here is the basic version of this. Converting this to a dynamic sql solution when the columns are unknown is going to be very tricky. You will need to use sql to dynamically generate a query similar to this. Any table that doesn't have a primary key, or a unique index would be nearly impossible because you wouldn't know what column to use as your group by. It also becomes more tricky because you don't know what datatype(s) you are working with. You would also need to be certain to add some logic to handle single quotes and NULL. This is an interesting challenge for sure. If I have time this weekend I may try to work something up for the dynamic version of this.
with Something(Id, FirstName, LastName) as
(
select 1, 'John', 'Doe' union all
select 2, 'Erik', 'Foo'
)
select STUFF((select cast(s2.Id as varchar(5)) + ', ' + s2.FirstName + ', ' + s2.LastName
from Something s2
where s2.Id = s.Id
for xml path('')), 1, 0, '') as Stuffed
from Something s
group by Id

Bulk Replace in SQL-Server

Is it possible to do bulk replace without while loop or what is the best way
Table-1
+-------+--------+
| name | value |
+-------+--------+
| #1# | one |
| #2# | two |
| #3# | three |
+-------+--------+
Table-2 (updated: there is more than one different tokens in table2)
+-----------------------+
| col1 |
+-----------------------+
| string #1# string #2# |
| string #2# string #1# |
| string #3# string #2# |
+-----------------------+
I like to replace all token from Table-2 with Table-1's value column respectively.
Expected Result
+-------------------------+
| col1 |
+-------------------------+
| string one string two |
| string two string one |
| string three string two |
+-------------------------+
Current solution with While loop
declare #table1 table(name nvarchar(50),value nvarchar(50))
insert into #table1 values('#1#','one'),('#2#','two'),('#1#','three')
declare #table2 table(col1 nvarchar(50))
insert into #table2 values('string #1# string #2#'),('string #2# string #1#'),('string #3# string #2#')
WHILE EXISTS (SELECT 1 FROM #table2 t2 INNER JOIN #table1 t1 ON CHARINDEX(t1.name,[col1])>0)
BEGIN
UPDATE #table2
SET col1=REPLACE(col1,name,value)
FROM #table1
WHERE CHARINDEX(name,[col1])>0
END
select * from #table2
Thanks
I suppose you use Sql Server (you've tagged with tsql):
I've run this query on Sql fiddle with 2012 version, but on my PC I've tried with 2008r2 version.
You can procede in this way:
UPDATE table2
SET col1 = REPLACE(col1,
(SELECT name FROM table1 WHERE col1 LIKE '%' + table1.NAME + '%'),
(SELECT value FROM table1 WHERE col1 LIKE '%' + table1.NAME + '%'))
Sql Fiddle
If you want show only the value without UPDATE you can proceed in this way:
SELECT REPLACE(T2.col1, T1.name, T1.value)
FROM table1 T1
JOIN table2 T2
ON T2.col LIKE '%' T1.name + '%'
EDIT
After editing of question / comment my answer is not complete because on the same row can exist more one token. I'm thinking... :)
I thought: :D
IMHO: You must create a loop on your table because the presence of several tokens don't resolve with a single UPDATE statement with subquery, because as you written, the subquery return more than one value.
In Sql Server the REPLACE function change only token, so if you want change in one step two token you must nest your REPLACE function, but we have a number undefined of token in a row so we can't prevent to apply the exact number of REPLACE. An help you can have using a cursor and a dynamic SQL query build on runtime, so you can do a single UPDATE per row. If you want a guide line to use CURSOR and DYNAMIC SQL, please write me. Good night ;)
You can do bulk replacement with this simple piece of code:
update #table2
set col1= left(a.col1,6)+' ' + b.value from #table2 a
join #table1 b on b.name=substring(a.col1,8,3)
select * from #table2
Basically, it updates the column with a new field value.

Resources