How to use select with a variable - sql

To simplify I have a table and I just want to make a select with the data at blue, is tricky for me because I must use the where textanswer='dimibilli d2' but I will only get the records 5, 7, 10, 12 but I want to get the 6, 8, 9 to
How can I do this?

select rows with required text column and match corresponding Id's to get required output.
declare #table table (transdocnumber int, textanswer varchar(20))
insert #table (transdocnumber,textanswer)
select 4631, 'Dimibilli D4' union all
select 4631, '' union all
select 5055, 'Dimibilli D2' union all
select 5055, '' union all
select 5270, 'Dimibilli D2' union all
select 5270, '' union all
select 5270, '' union all
select 5513, 'Dimibilli D2' union all
select 6279, 'Dimibilli D4' union all
select 6616, 'Dimibilli D2' union all
select 6773, 'Dimibilli D4'
select t.transdocnumber,t.textanswer from (
select transdocnumber from #table where textanswer = 'Dimibilli D2' ) x
inner join #table t on x.transdocnumber = t.transdocnumber where t.textanswer = ''
union all
select transdocnumber,textanswer from #table where textanswer = 'Dimibilli D2'
order by transdocnumber
Solution:
SELECT t.transdocnumber, t.extrafield_id, t.textanswer, t.BooleanAnswer, t.DtAlt
FROM (
SELECT *
FROM TABLE
WHERE textanswer = 'Dimibilli D2'
) x
INNER JOIN TABLE t ON x.transdocnumber = t.transdocnumber
WHERE t.textanswer = ''
UNION ALL
SELECT transdocnumber, extrafield_id, textanswer, BooleanAnswer, DtAlt
FROM TABLE
WHERE textanswer = 'Dimibilli D2'
ORDER BY transdocnumber

You seem to want:
select t.*
from t
where t.tansdocnumber in (select t2.transdocnumber from t t2 where t2.textanswer = 'Dimobili D2);

select * from table
where textanswer not in ('dimobilli d4')

for what I have understood you want to get back rows with textanswer='dimibilli d2' and textanswer='dimibilli d2' but not row 4.
You can't do that in this way, you should differentiate the row that you want in some way.
using
select * from table
where (textanswer='dimibilli d2' or textanswer = '')
as Ven suggested you will have line 4,5,6,7,8,9,10,12 as result, but it seems that you want only 5,6,7,8,9,10,12
for example you can use:
select * from table
where (textanswer='dimibilli d2' or textanswer = '') and TransDocNumber>5000;
this should work

Try to use the below query:
select * from table
where (TextAnswer='Dimobili D2' or BooleanAnswer = '1') and TextAnswer!=''

Related

Print result by merging records in a table

I have a table with name "PrintWord" and column name as col_letter and data in it is as follows:
"col_letter"
S
A
C
H
I
N
I would like to print the o/p from this table as:
SACHIN
Thanks!
DECLARE #t table
(
Name varchar(10)
)
INSERT INTO #t
SELECT 's' UNION ALL
SELECT 'a' UNION ALL
SELECT 'c' UNION ALL
SELECT 'h' UNION ALL
SELECT 'i' UNION ALL
SELECT 'n'
SELECT DISTINCT
stuff(
(
SELECT ' '+ [Name] FROM #t FOR XML PATH('')
),1,1,'')
FROM (SELECT DISTINCT Name FROM #t ) t
There is a hard-coded version :
SELECT col_letter
FROM PrintWord
ORDER BY
CASE col_letter
WHEN 'S' THEN 1
WHEN 'A' THEN 2
WHEN 'C' THEN 3
WHEN 'H' THEN 4
WHEN 'I' THEN 5
WHEN 'N' THEN 6
END
FOR XML PATH('')
You need an ORDER BY clause to guarantee the order of the letters.

SQL splitting a word in separate characters

I need to change an application and the first thing I need is to change a field in a database table.
In this table I now have 1 to 6 single characters, i.e. 'abcdef'
I need to change this to '[a][b][c][d][e][f]'
[edit] It is meant to stay in the same field. So before field = 'abcdef' and after field = '[a][b][c][d][e][f]'.
What would be a good way to do this?
rg.
Eric
You can split string to separate characters using following function:
create function ftStringCharacters
(
#str varchar(100)
)
returns table as
return
with v1(N) as (
select 1 union all select 1 union all select 1 union all select 1 union all select 1
union all
select 1 union all select 1 union all select 1 union all select 1 union all select 1
),
v2(N) as (select 1 from v1 a, v1 b),
v3(N) as (select top (isnull(datalength(#str), 0)) row_number() over (order by ##spid) from v2)
select N, substring(#str, N, 1) as C
from v3
GO
And then apply it as:
update t
set t.FieldName = p.FieldModified
from TableName t
cross apply (
select (select quotename(s.C)
from ftStringCharacters(t.FieldName) s
order by s.N
for xml path(''), type).value('text()[1]', 'varchar(20)')
) p(FieldModified)
SQLFiddle sample
DECLARE #text NVARCHAR(50)
SET #text = 'abcdef'
DECLARE #texttable TABLE (value NVARCHAR(1))
WHILE (len(#text) > 0)
BEGIN
INSERT INTO #texttable
SELECT substring(#text, 1, 1)
SET #text = stuff(#text, 1, 1, '')
END
select * from #texttable
Without using a function:
declare #t table(C varchar(18))
insert #t values('abc'), ('1234'), (' 1234a')
;with CTE as
(
select C, '[' + substring(c, a.n, 1) + ']' v, rn from
(select 1 n union all
select 2 union all
select 3 union all
select 4 union all
select 5 union all
select 6) a
cross apply
(select c, row_number() over (order by C) rn from #t group by c) b
where a.n <= len(C)
)
update t3
set C = t4.[value]
FROM #t t3
JOIN
(
select C,
(
select v
from CTE t1
where t1.rn = t2.rn
for xml path(''), type
).value('.', 'varchar(18)') [value]
from CTE t2
group by t2.rn, C
) t4
ON t3.C = t4.C
SELECT * FROM #t

SQL multiple replace

I want to read the company table and take out all possible suffixes from the name. Here's what I have so far:
declare #badStrings table (item varchar(50))
INSERT INTO #badStrings(item)
SELECT 'company' UNION ALL
SELECT 'co.' UNION ALL
SELECT 'incorporated' UNION ALL
SELECT 'inc.' UNION ALL
SELECT 'llc' UNION ALL
SELECT 'llp' UNION ALL
SELECT 'ltd'
select id, (companyname = Replace(name, item, '') FROM #badStrings)
from companies
where name != ''
Ed Northridge's answer will work, and I have upvoted it, but just in case multiple replacements are required I am adding another option using his sample data. If, for example one of the companies was called "The PC Company LTD" This would duplicate rows in the output with one being "The PC LTD" and the other "The PC Company". To resolve this there are 2 option depending on your desired outcome. The first is to only replace the "Bad Strings" when they occur at the end of the name.
SELECT c.ID, RTRIM(x.Name) [Name]
FROM #companies c
OUTER APPLY
( SELECT REPLACE(c.name, item, '') AS [Name]
FROM #badStrings
-- WHERE CLAUSE ADDED HERE
WHERE CHARINDEX(item, c.Name) = 1 + LEN(c.Name) - LEN(Item)
) x
WHERE c.name != ''
AND x.[Name] != c.Name
This would yield "The PC Company" with no duplicates.
The other option is replace All occurances of the Bad Strings recursively:
;WITH CTE AS
( SELECT c.ID, c.Name [OriginalName], RTRIM(x.Name) [Name], 1 [Level]
FROM #companies c
OUTER APPLY
( SELECT REPLACE(c.name, item, '') AS [Name]
FROM #badStrings
WHERE CHARINDEX(item, c.Name) = 1 + LEN(c.Name) - LEN(Item)
) x
WHERE c.name != ''
AND RTRIM(x.Name) != c.Name
UNION ALL
SELECT c.ID, OriginalName, RTRIM(x.Name) [Name], Level + 1 [Level]
FROM CTE c
OUTER APPLY
( SELECT REPLACE(c.name, item, '') AS [Name]
FROM #badStrings
WHERE CHARINDEX(item, c.Name) = 1 + LEN(c.Name) - LEN(Item)
) x
WHERE c.name != ''
AND x.[Name] != c.Name
)
SELECT DISTINCT ID, Name, OriginalName
FROM ( SELECT *, MAX(Level) OVER(PARTITION BY ID) [MaxLevel]
FROM CTE
) c
WHERE Level = maxLevel
This would yield "The PC" from "The PC Company".
The error I got running the snippet was:
Msg 102, Level 15, State 1, Line 12
Incorrect syntax near '='.
The below code isn't an ideal solution - it will only return a list of companies where their name has been changed by the REPLACE function.
declare #companies table (id int, name nvarchar(50))
INSERT INTO #companies(id, name)
SELECT 1,'One Company' UNION ALL
SELECT 2, 'Two co.' UNION ALL
SELECT 3, 'Three incorporated' UNION ALL
SELECT 4, 'Four inc.' UNION ALL
SELECT 5, 'Five llc' UNION ALL
SELECT 6, 'Six llp' UNION ALL
SELECT 7, 'Seven ltd'
select * from #companies
declare #badStrings table (item varchar(50))
INSERT INTO #badStrings(item)
SELECT 'company' UNION ALL
SELECT 'co.' UNION ALL
SELECT 'incorporated' UNION ALL
SELECT 'inc.' UNION ALL
SELECT 'llc' UNION ALL
SELECT 'llp' UNION ALL
SELECT 'ltd'
select * from #badStrings
Here is the edited query:
select id, x.Name
from #companies c
OUTER APPLY (
SELECT Replace(c.name, item, '') AS [Name]
FROM #badStrings
) x
where c.name != ''
AND x.[Name] != c.Name
This returns:
id Name
----------- --------
1 One
2 Two
3 Three
4 Four
5 Five
6 Six
7 Seven
(7 row(s) affected)
Hopefully it's useful
Edit:
An alternative to apply the match to those company names which end with the #badStrings value
select id, x.Name
from #companies c
OUTER APPLY (
SELECT Replace(c.name, item, '') AS [Name]
FROM #badStrings
WHERE c.Name LIKE '%'+item
) x
where c.name != ''

SQL query problem

Let´s say I have two tables, "Garden" and "Flowers". There is a 1:n-relationship between these tables, because in a garden can be many flowers. Is it possible to write an SQL query which returns a result with the following structure:
GardenName Flower1Name Flower2Name .... (as long as there are entries in flowers)
myGarden rose tulip
CREATE TABLE #Garden (Id INT, Name VARCHAR(20))
INSERT INTO #Garden
SELECT 1, 'myGarden' UNION ALL
SELECT 2, 'yourGarden'
CREATE TABLE #Flowers (GardenId INT, Flower VARCHAR(20))
INSERT INTO #Flowers
SELECT 1, 'rose' UNION ALL
SELECT 1, 'tulip' UNION ALL
SELECT 2, 'thistle'
DECLARE #ColList nvarchar(max)
SELECT #ColList = ISNULL(#ColList + ',','') + QUOTENAME('Flower' + CAST(ROW_NUMBER() OVER (ORDER BY (SELECT 0)) AS VARCHAR))
FROM #Flowers WHERE GardenId = (
SELECT TOP 1 GardenId
FROM #Flowers
ORDER BY COUNT(*) OVER (PARTITION BY GardenId) DESC
)
EXEC (N'
;WITH cte As
(
SELECT *, ''Flower'' + CAST(ROW_NUMBER() OVER (PARTITION BY GardenId ORDER BY (SELECT 0)) AS VARCHAR) RN
FROM #Flowers F
)
SELECT Name,' + #ColList + N'
FROM cte
JOIN #Garden g ON g.Id = GardenId
PIVOT (MAX(Flower) FOR RN IN (' + #ColList + N')) Pvt')
DROP TABLE #Garden
DROP TABLE #Flowers
Returns
Name Flower1 Flower2
-------------------- -------------------- --------------------
myGarden rose tulip
yourGarden thistle NULL
Look at using Pivot in SQL Server. Here is a good link that goes over how it works:
http://www.kodyaz.com/articles/t-sql-pivot-tables-in-sql-server-tutorial-with-examples.aspx
Ok, i think i got it working. Try this:
with temp as
(
select 'myGarden' as name, 'test1' as flower
union
select 'myGarden','test2'
union
select 'myGarden','test5'
union
select 'abeGarden','test4'
union
select 'abeGarden','test5'
union
select 'martinGarden', 'test2'
)
select* from temp
pivot
(
max(flower)
for flower in (test1,test2,test3,test4,test5)
) PivotTable
You could also make the values in the in clause dynamic. Since this is a CTE i can't in my example.
Dynamic SQL with a cursor is the only way I can think of, and it won't be pretty.
If you only want the results for one garden at a time this would give you the data:
select gardenName from tblGarden where gardenid = 1
Union ALL
select tblFLowers.flowerName from tblFlowers where gardenid = 1

CTE error: "Types don't match between the anchor and the recursive part"

I am executing the following statement:
;WITH cte AS (
SELECT
1 as rn,
'name1' as nm
UNION ALL
SELECT
rn + 1,
nm = 'name' + CAST((rn + 1) as varchar(255))
FROM cte a WHERE rn < 10)
SELECT *
FROM cte
...which finishes with the error...
Msg 240, Level 16, State 1, Line 2
Types don't match between the anchor and the recursive part in column "nm" of recursive query "cte".
Where am I making the mistake?
Exactly what it says:
'name1' has a different data type to 'name' + CAST((rn+1) as varchar(255))
Try this (untested)
;with cte as
(
select 1 as rn, CAST('name1' as varchar(259)) as nm
union all
select rn+1,nm = 'name' + CAST((rn+1) as varchar(255))
from cte a where rn<10)
select * from cte
Basically, you have to ensure the length matches too. For the recursive bit, you may have to use CAST('name' AS varchar(4)) if it fails again
You need to cast both nm fields
;with cte as
(
select 1 as rn,
CAST('name1' AS VARCHAR(255)) as nm
union all
select rn+1,
nm = CAST('name' + CAST((rn+1) as varchar(255)) AS VARCHAR(255))
from cte a where rn<10)
select * from cte
For me problem was in different collation.
Only this helped me:
;WITH cte AS (
SELECT
1 AS rn,
CAST('name1' AS NVARCHAR(4000)) COLLATE DATABASE_DEFAULT AS nm
UNION ALL
SELECT
rn + 1,
nm = CAST('name' + CAST((rn + 1) AS NVARCHAR(255)) AS NVARCHAR(4000)) COLLATE DATABASE_DEFAULT
FROM cte a WHERE rn < 10)
SELECT *
FROM cte;
Hope it can help someone else.
;with cte as
(
select 1 as rn, 'name' + CAST(1 as varchar(255)) as nm
union all
select rn+1,nm = 'name' + CAST((rn+1) as varchar(255))
from cte a where rn<10)
select * from cte
In my case, I messed up the sequence of columns in top and bottom clauses of UNION ALL. And it turned out that a varchar column appeared 'under' an int one. An easy mistake to make of you have lots of columns
If you use CONCAT in the recursive term of a rcte, since the output type of concat is varchar(MAX), you only need to cast the column in the initial query:
WITH rcte AS (
SELECT 1 AS nr, CAST('1' AS varchar(MAX)) AS trail
UNION ALL
SELECT nr+1, CONCAT(trail, '/', nr+1)
FROM rcte
WHERE nr < 5
)
SELECT * FROM rcte;
I would recommend using nvarchar(max)
WITH CTE AS (
SELECT x,x_name FROM (VALUES (1,CAST('' AS nvarchar(MAX)))) AS test(x,x_name)
UNION ALL
SELECT x + 1 x, CONCAT(x_name,x+1) FROM CTE WHERE x < 10 )
SELECT * FROM CTE
WITH rcte AS (
SELECT 1 AS nr, CAST('1' AS varchar(MAX)) AS trail
UNION ALL
SELECT nr+1, cast(CONCAT(trail, '/', nr+1) as varchar(max))
FROM rcte
WHERE nr < 5
)
SELECT * FROM rcte;
;with tmp1(NewsId,DataItem ,HeaderText)
as
(
select NewsId, LEFT(HeaderText, CHARINDEX(',',HeaderText+',')-1),
STUFF(HeaderText, 1, CHARINDEX(',',HeaderText+','), '')
from Currentnews
union all
select NewsId, LEFT(HeaderText, CHARINDEX(',',HeaderText+',')-1),
STUFF(HeaderText, 1, CHARINDEX(',',HeaderText+','), '')
from tmp1
where HeaderText > ''
)
select NewsId, DataItem
from tmp1
order by NewsId