How to find other than current value in SQL Server? - sql-server

In SQL Server, how can I get data from a column other than specified data.
For example, I have a column with data "MySQL,Server,Database" in single row.
Now I want to find if there is any other value than MySQL in that column.
I tried by using Not Like but didn't succeed.
For example TableA :
id | Code
---+---------------------------
1 | mysql,sqlserver,database
2 | mysql
3 | sqlserver,database
4 | mysql,mysql
Here, I want to find if the column has data other than "mysql" or not, like id:1 has data other than "mysql" but id:2 have "mysql" but not other than "mysql".
Finally if I want to return the null or blank value if there no any data other than "mysql".
Code I used so far :
select code from tableA where code not like '%mysql%'

It helps if you can provide some data and some code. This works (as far as I understand the question):
CREATE TABLE #x (object_type varchar(50))
INSERT #x (object_type) VALUES ('MySQL'), ('Server'), ('Database')
SELECT * FROM #x WHERE object_type <> 'MySQL'
Base on the updated question, I think you're looking for:
CREATE TABLE #x (id int identity(1, 1), code varchar(50))
INSERT #x (code) VALUES ('mysql,sqlserver,database'), ('mysql'), ('sqlserver,database'), ('mysql,mysql')
SELECT *
FROM #x
WHERE id IN (
SELECT id
FROM #x
CROSS APPLY string_split(code, ',')
WHERE value <> 'mysql'
)
However, as #Eric Brandt asked above, it's not clear whether you want to select row id = 4.

Note STRING_SPLIT is only available for SQL Server 2016 or later. if you are using a earlier version, do a search, there are lots of similar implementation
declare #table table
(
id int identity,
Code varchar(30)
)
insert into #table select 'mysql,sqlserver,database'
insert into #table select 'mysql'
insert into #table select 'sqlserver,database'
insert into #table select 'mysql,mysql'
insert into #table select ''
insert into #table select NULL
select *
from #table t
where t.Code is null
or exists
(
select *
from string_split(t.Code, ',')
where value <> 'mysql'
)
/* RESULT
1 mysql,sqlserver,database
3 sqlserver,database
5
6 NULL
*/

Related

Dynamic approach in Azure SQL DW to get only those column names from a table whose values are not null for a particular record

I have the table structure something like below
Number Of Columns are more than 150.
Basically, I would want to query the table for a particular record say ID = 1 and It should return all column names which are not empty.
I am expecting the below output where in I should be able to fetch/show only those column names whose values are not null for a particular record.
Kindly note that I am trying to achieve this in Azure SQL DW that doesn't support FOR XML Path clause, Cursor, very limited dynamic SQL functionality.
UNPIVOT works, and you don't have to filter because "null values in the input of UNPIVOT disappear in the output", eg
create table #t(id int, col_1 char(1), col_2 char(1), col_3 char(1))
insert into #t values (1,'A',null,'G')
insert into #t values (2,'A','c', null)
select id, col, val
from
( select * from #t ) p
unpivot
( Val for Col in (col_1, col_2, col_3 ) ) as unpvt
order by id, col;
In Synapse SQL On-Demand You can also do this by using FOR JSON / OPENJSON to pivot.
Like this
create table #t(id int, col_1 char(1), col_2 char(1), col_3 char(1))
insert into #t values (1,'A',null,'G')
select [key] columnName
from openjson(
(
select * from #t
where id = 1
for json path, WITHOUT_ARRAY_WRAPPER
)) d
where value is not null
and [key] <> 'id'
outputs
So Synapse SQL Pools (aka Azure SQL DW) should enentually get this too.

Multiple XML tag value into single column with comma separator

I have an XML where the XML have multiple similar tag and I want this value need to show in one column with comma separator and insert into table.
For example:
<test xmlns="http://www.google.com">
<code>a</code>
<code>b</code>
<code>c</code>
</test>
Since XML is too large and I am using OPENXML to perform operation and insert that value into particular table.
I am performing like
insert into table A
(
code
)
select Code from OPENXML(sometag)
with (
code varchar(100) 'tagvalue'
)
for XQUERY I am using something like this: 'for $i in x:Code return concat($i/text()[1], ";")' and I want same with OPENXML.
Output: I want code tag value into one column like a,b,c or a/b/c.
Since you're on SQL Server 2017 you could use STRING_AGG (Transact-SQL) to concatenate your code values, e.g.:
create table dbo.Test (
someTag xml
);
insert dbo.Test (someTag) values
('<test><code>a</code><code>b</code><code>c</code></test>'),
('<test><code>d</code><code>e</code><code>f</code></test>');
select [Code], [someTag]
from dbo.Test
outer apply (
select [Code] = string_agg([value], N',')
from (
select n1.c1.value('.', 'nvarchar(100)')
from someTag.nodes(N'/test/code') n1(c1)
) src (value)
) a1;
Which yields...
Code someTag
a,b,c <test><code>a</code><code>b</code><code>c</code></test>
d,e,f <test><code>d</code><code>e</code><code>f</code></test>
Just a small tweak to AlwaysLearning (+1)
Example
Declare #YourTable table (ID int,XMLData xml)
insert Into #YourTable values
(1,'<test><code>a</code><code>b</code><code>c</code></test>')
Select A.ID
,B.*
From #YourTable A
Cross Apply (
Select DelimString = string_agg(xAttr.value('.','varchar(max)'),',')
From A.XMLData.nodes('/test/*') xNode(xAttr)
) B
Returns
ID DelimString
1 a,b,c
And just for completeness, here is method #3 via pure XQuery and FLWOR expression.
SQL
-- DDL and sample data population, start
DECLARE #tbl TABLE (ID INT IDENTITY PRIMARY KEY, xmldata xml);
INSERT #tbl (xmldata) VALUES
('<test xmlns="http://www.google.com"><code>a</code><code>b</code><code>c</code></test>'),
('<test xmlns="http://www.google.com"><code>d</code><code>e</code><code>f</code></test>');
-- DDL and sample data population, end
DECLARE #separator CHAR(1) = ',';
-- Method #3
-- SQL Server 2005 onwards
;WITH XMLNAMESPACES (DEFAULT 'http://www.google.com')
SELECT ID
, xmldata.query('for $i in /test/code
return if ($i is (/test/code[last()])[1]) then string($i)
else concat($i, sql:variable("#separator"))')
.value('.', 'NVARCHAR(MAX)') AS [Comma_separated_list]
FROM #tbl;
Output
+----+----------------------+
| ID | Comma_separated_list |
+----+----------------------+
| 1 | a, b, c |
| 2 | d, e, f |
+----+----------------------+

Table variable error: Must declare the scalar variable "#temp"

I am trying to achieve:
declare #TEMP table (ID int, Name varchar(max))
insert into #temp SELECT ID, Name FROM Table
SELECT * FROM #TEMP
WHERE #TEMP.ID = 1 <--- ERROR AT #TEMP.ID
But I'm getting the following error:
Must declare the scalar variable "#temp".
What am I doing wrong?
A table alias cannot start with a #. So, give #Temp another alias (or leave out the two-part naming altogether):
SELECT *
FROM #TEMP t
WHERE t.ID = 1;
Also, a single equals sign is traditionally used in SQL for a comparison.
Either use an Allias in the table like T and use T.ID, or use just the column name.
declare #TEMP table (ID int, Name varchar(max))
insert into #temp SELECT ID, Name FROM Table
SELECT * FROM #TEMP
WHERE ID = 1
There is one another method of temp table
create table #TempTable (
ID int,
name varchar(max)
)
insert into #TempTable (ID,name)
Select ID,Name
from Table
SELECT *
FROM #TempTable
WHERE ID = 1
Make Sure You are selecting the right database.
If you bracket the # you can use it directly
declare #TEMP table (ID int, Name varchar(max))
insert into #temp values (1,'one'), (2,'two')
SELECT * FROM #TEMP
WHERE [#TEMP].[ID] = 1
You should use hash (#) tables, That you actually looking for because variables value will remain till that execution only.
e.g. -
declare #TEMP table (ID int, Name varchar(max))
insert into #temp SELECT ID, Name FROM Table
When above two and below two statements execute separately.
SELECT * FROM #TEMP
WHERE #TEMP.ID = 1
The error will show because the value of variable lost when you execute the batch of query second time.
It definitely gives o/p when you run an entire block of code.
The hash table is the best possible option for storing and retrieving the temporary value. It last long till the parent session is alive.
try the following query:
SELECT ID,
Name
INTO #tempTable
FROM Table
SELECT *
FROM #tempTable
WHERE ID = 1
It doesn't need to declare table.
You could stil use #TEMP if you quote the identifier "#TEMP":
declare #TEMP table (ID int, Name varchar(max));
insert into #temp SELECT 1 AS ID, 'a' Name;
SELECT * FROM #TEMP WHERE "#TEMP".ID = 1 ;
db<>fiddle demo
You've declared #TEMP but in your insert statement used #temp. Case sensitive variable names.
Change #temp to #TEMP

tsql return identity values when inserting multiple records into a view

I have a situation where I need to insert multiple records/batch insert into a view which has instead of trigger. How can I retrieve the inserted identity values? I tried using the OUTPUT clause to retrieve the Id from the Inserted table but it always returns null.
Using this setup.
create table InsteadOf
(
ID int identity primary key,
Name varchar(10) not null
)
go
create view v_InsteadOf
as
select ID, Name
from InsteadOf
go
create trigger tr_InsteadOf on InsteadOf instead of insert
as
begin
insert into InsteadOf(Name)
select Name
from inserted
end
The statement
insert into v_InsteadOf(Name)
output inserted.*
select 'Name1' union all
select 'Name2'
Will give you an error.
Msg 334, Level 16, State 1, Line 4 The target table 'InsteadOf' of the
DML statement cannot have any enabled triggers if the statement
contains an OUTPUT clause without INTO clause.
Using an INTO clause with the insert instead.
declare #IDs table(ID int, Name varchar(10))
insert into v_InsteadOf(Name)
output inserted.* into #IDs
select 'Name1' union all
select 'Name2'
select *
from #IDs
Gives you 0 as a value not null.
ID Name
----------- ----------
0 Name1
0 Name2
You can put the output clause in the trigger.
create trigger tr_InsteadOf on InsteadOf instead of insert
as
begin
insert into InsteadOf(Name)
output inserted.*
select Name
from inserted
end
And the output will be generated for you when you do the insert.
insert into v_InsteadOf(Name)
select 'Name1' union all
select 'Name2'
Result:
ID Name
----------- ----------
1 Name1
2 Name2
Update:
To capture the output from the insert statement you can use insert into ... exec (...)
declare #T table
(
ID int,
Name varchar(10)
)
insert into #T
exec
(
'insert into v_InsteadOf(Name)
values (''Name1''),(''Name2'')'
)

contains search over a table variable or a temp table

i'm trying to concatenate several columns from a persistent table into one column of a table variable, so that i can run a contains("foo" and "bar") and get a result even if foo is not in the same column as bar.
however, it isn't possible to create a unique index on a table variable, hence no fulltext index to run a contains.
is there a way to, dynamically, concatenate several columns and run a contains on them? here's an example:
declare #t0 table
(
id uniqueidentifier not null,
search_text varchar(max)
)
declare #t1 table ( id uniqueidentifier )
insert into
#t0 (id, search_text)
select
id,
foo + bar
from
description_table
insert into
#t1
select
id
from
#t0
where
contains( search_text, '"c++*" AND "programming*"' )
You cannot use CONTAINS on a table that has not been configured to use Full Text Indexing, and that cannot be applied to table variables.
If you want to use CONTAINS (as opposed to the less flexible PATINDEX) you will need to base the whole query on a table with a FT index.
You can't use full text indexing on a table variable but you can apply the full text parser. Would something like this do what you need?
declare #d table
(
id int identity(1,1),
testing varchar(1000)
)
INSERT INTO #D VALUES ('c++ programming')
INSERT INTO #D VALUES ('c# programming')
INSERT INTO #D VALUES ('c++ books')
SELECT id
FROM #D
CROSS APPLY sys.dm_fts_parser('"' + REPLACE(testing,'"','""') + '"', 1033, 0,0)
where display_term in ('c++','programming')
GROUP BY id
HAVING COUNT(DISTINCT display_term)=2
NB: There might well be a better way of using the parser but I couldn't quite figure it out. Details of it are at this link
declare #table table
(
id int,
fname varchar(50)
)
insert into #table select 1, 'Adam James Will'
insert into #table select 1, 'Jain William'
insert into #table select 1, 'Bob Rob James'
select * from #table where fname like '%ja%' and fname like '%wi%'
Is it something like this.

Resources