Comparing Results From Two Different Queries Based on Common Field - sql-server

Ok, so I just started working with SQL so please be easy on me if there's a super easy solution that I just don't know. I'm using Microsoft SQL Server. I have two queries that give me results, one being
EXEC ('SELECT ID ,
Type,
Date
FROM DB2T.BBT') AT DB2
and the other being
select
ca.value('(/CA[#name=''ID'']/#value)[1]','VARCHAR(MAX)') as ID,
ca.value('(/CA[#name=''Type'']/#value)[1]', 'VARCHAR(MAX)') as Type,
ca.value('(/CA[#name=''Date'']/#value)[1]', 'VARCHAR(MAX)') as Date,
from log
This is just how I extract the relevant data from the places I need. I end up with two different queries with two different table outputs, each row containing an ID, Type, and Date.
I need to combine these two queries so I can compare the two tables. I need to see, depending on matching IDs from the two queries, if the values for Type and Date are equal. I only want to output IDs that have differing values and then output the differing values with it.
So I have two problems I guess, one being combining the two queries and then doing the comparing. Thanks in advance.

This query will combine the resultsets into one, then group by the ID, Type, and Date columns and pull back which ones don't have two rows (should have one from DB2 and one from SQL). It doesn't tell you exactly what is different but should be pretty easy to tell with that few columns.
SELECT
MIN(System) AS System,
ID,
Type,
Date
FROM (
select
'SQL',
ca.value('(/CA[#name=''ID'']/#value)[1]','VARCHAR(MAX)') as ID,
ca.value('(/CA[#name=''Type'']/#value)[1]', 'VARCHAR(MAX)') as Type,
ca.value('(/CA[#name=''Date'']/#value)[1]', 'VARCHAR(MAX)') as Date,
from log
UNION ALL
SELECT 'DB2', * FROM OPENQUERY([DB2], ''SELECT ID, Type, Date FROM DB2T.BBT'')
) compare
GROUP BY ID, Type, Date
HAVING COUNT(*) <> 2
ORDER BY ID, Type, Date

Basically, break it down into 2 queries. The first one is qry1, the second is qry2. You want to use an inner join, because you only want values where Type and Date are equal. Then, you use a WHERE clause to give you only the records where ID doesn't match.
You may have to put ID in brackets, I can't remember off the top of my head if that's a reserved word or not. I know both Date and Type are reserved words, and that's why I put them in brackets.
SELECT
qry1.ID as ID1,
qry1.[Type] as Type1,
qry1.[Date] as Date1,
qry2.ID as ID2,
qry2.[Type] as Type2,
qry2.[Date] as Date2
FROM
(SELECT ID, Type, Date
FROM DB2T.BBT) as qry1,
INNER JOIN
(select
ca.value('(/CA[#name=''ID'']/#value)[1]','VARCHAR(MAX)') as ID,
ca.value('(/CA[#name=''Type'']/#value)[1]', 'VARCHAR(MAX)') as Type,
ca.value('(/CA[#name=''Date'']/#value)[1]', 'VARCHAR(MAX)') as Date,
from log) as qry2
ON qry1.[Type] = qry2.[Type]
AND qry1.[Date] = qry2.[Date]
WHERE qry1.ID <> qry2.ID

What about comparing computed columns that are hashes of the concatenated column values? Something like this:
declare #t1 table (id int, type varchar(max), dt date, hash_bytes as HASHBYTES('SHA1', CAST(id AS NVARCHAR(MAX)) + CAST(type AS NVARCHAR(MAX)) + CAST(dt AS NVARCHAR(MAX))))
declare #t2 table (id int, type varchar(max), dt date, hash_bytes as HASHBYTES('SHA1', CAST(id AS NVARCHAR(MAX)) + CAST(type AS NVARCHAR(MAX)) + CAST(dt AS NVARCHAR(MAX))))
insert into #t1 values
(1, 'val1', getdate()), -- no match in #t2
(2, 'val2', getdate() + 1),
(3, 'val3', getdate() + 2),
(4, 'val4', getdate() + 3),
(5, 'val5', getdate() + 4)
insert into #t2 values
(2, 'val2', getdate() + 1), -- same
(3, 'val300', getdate() + 2), -- different type
(4, 'val4', getdate() + 300), -- different date
(5, 'val500', getdate() + 400),-- different type & date
(6, 'val6', getdate() + 5) -- no match in #t1
select *
from #t1 t1
full join #t2 t2 on t1.hash_bytes = t2.hash_bytes
id type dt hash_bytes id type dt hash_bytes
1 val1 2018-07-27 0xF53D672F572DC49D15AE2ECD2F3225624073FEB8 NULL NULL NULL NULL
2 val2 2018-07-28 0x8840035CC198447CB1F9D85E97A57F2B08ADB39E 2 val2 2018-07-28 0x8840035CC198447CB1F9D85E97A57F2B08ADB39E
3 val3 2018-07-29 0x372E6A3B48C3C96C2456A514CD9D35CAC4EEEACE NULL NULL NULL NULL
4 val4 2018-07-30 0xE91A2E58D2964BB3BE6BDD1C1ECA3628E956484D NULL NULL NULL NULL
5 val5 2018-07-31 0xB289831856A15334BE60EC4F78502052B15EE4CD NULL NULL NULL NULL
NULL NULL NULL NULL 3 val300 2018-07-29 0x2007D7205352EE65013DC21E527780E1FED763D8
NULL NULL NULL NULL 4 val4 2019-05-23 0x60CC2C7B3902204E82F137401446EB974EC83C3B
NULL NULL NULL NULL 5 val500 2019-08-31 0xFFF8FD045B306B3F1663FC4903CE859A6C9577FB
NULL NULL NULL NULL 6 val6 2018-08-01 0x72407548472D00C87E6DDF42A05E0B1B687AACBA

Related

Ignoring rows within daterange

I have the following data:
CREATE TABLE SampleData
(
orderid int,
[name] nvarchar(1),
[date] date
);
INSERT INTO SampleData
VALUES
(1, 'a', '2017-01-01'),
(2, 'a', '2017-01-05'),
(3, 'a', '2017-02-01'),
(4, 'a', '2017-04-01'),
(5, 'a', '2017-10-01'),
(6, 'b', '2017-04-01');
I need to retrieve each new order according to the following rules:
The first date for a name is the 'current order' for that name
Orders with the same name, but less than 3 months difference with the 'current order' is considered the same order and needs to be ignored
3 months or more difference with the 'current' order is considered a new order and is now the 'current order' (in the SampleData orderid 1 and 4 need to be compared instead of 3 and 4, because 3 is not the current order)
If the name and date are the same, then the row with the lowest orderid is the superior order
So with the sample data I need the following result:
id name, date
1 a 2017-01-01
4 a 2017-04-01
5 a 2017-10-01
6 b 2017-04-01
I tried several approaches, but without success. Any idea's on how I can achieve this?
Below is a quick fix solution that can be built upon if your code scales beyond the sample data provided. I will state beforehand that this isn't the prettiest solution but it does return the result set you indicated you were after.
If anything, you may want to consider looking into T-SQL Window Functions as well as Analytic Functions. I will advice that that they don't play well with all datatypes.
My goal with the solution below was to rank the rows while partitioning by name and order by the date field. Thus you have something similar to your order id but the rank is specific to the customer who placed the order.
I'll do my best to answer any questions:
if object_id('tempdb..#tmp_SampleData','u') is not null
drop table #tmp_SampleData
CREATE TABLE #tmp_SampleData
(
orderid int,
[name] nvarchar(1),
[date] date
);
INSERT INTO #tmp_SampleData
VALUES
(1, 'a', '2017-01-01'),
(2, 'a', '2017-01-05'),
(3, 'a', '2017-02-01'),
(4, 'a', '2017-04-01'),
(5, 'a', '2017-10-01'),
(6, 'b', '2017-04-01');
if object_id('tempdb..#tmp_iter','u') is not null
drop table #tmp_iter
select
orderid
,name
,date
,rank() over (partition by name order by date) [Rank]
,lag(orderid,1,0) over (partition by name order by date) [LagRank]
--,rank() over (partition by name order by date desc) [ReverseRank]
into #tmp_Iter
from #tmp_SampleData
if object_id('tempdb..#tmp_final','u') is not null
drop table #tmp_final
select
i.orderid
,i.name
,i.date
,datediff(month,i.date,i2.date) [MonthsPassed]
into #tmp_final
from #tmp_Iter i
left join #tmp_Iter i2
on i.Rank = i2.LagRank
select *
from #tmp_final
where 1=1
and MonthsPassed > 3
or MonthsPassed = 0
or MonthsPassed < 0
or MonthsPassed is null
#SQLUser44, thanks for your input. Unfortunately your code is not working. The result for the table below should be orderid's 1,6,7,8 and 9. Yours results in 1,2,3,5,6,7,8 and 9.
INSERT INTO #tmp_SampleData
VALUES
(1,'a','2017-01-01'),
(2,'a','2017-01-08'),
(3,'a','2017-05-01'),
(4,'a','2017-01-05'),
(5,'a','2017-02-01'),
(6,'b','2017-01-01'),
(7,'b','2017-09-01'),
(8,'c','2017-10-01'),
(9,'a','2017-04-01');
I came up with the following that works, but I think it will lack performance...
if object_id('tempdb..#tmp_SampleData','u') is not null
drop table #tmp_SampleData
CREATE TABLE #tmp_SampleData
(
orderid int,
[name] nvarchar(1),
[date] date
);
INSERT INTO #tmp_SampleData
VALUES
(1,'a','2017-01-01'),
(2,'a','2017-01-08'),
(3,'a','2017-05-01'),
(4,'a','2017-01-05'),
(5,'a','2017-02-01'),
(6,'b','2017-01-01'),
(7,'b','2017-09-01'),
(8,'c','2017-10-01'),
(9,'a','2017-04-01');
DECLARE Test_Cursor CURSOR FOR
SELECT * FROM #tmp_SampleData ORDER BY [name], [date];
OPEN Test_Cursor;
DECLARE #orderid int;
DECLARE #name nvarchar(255);
DECLARE #date date;
FETCH NEXT FROM Test_Cursor INTO #orderid, #name, #date;
DECLARE #current_date date = #date;
DECLARE #current_name nvarchar(255) = #name;
DECLARE #listOfIDs TABLE (orderid int);
INSERT #listOfIDs values(#orderid);
WHILE ##FETCH_STATUS = 0
BEGIN
IF(#name = #current_name AND DATEDIFF(MONTH, #current_date, #date) >= 3)
BEGIN
SET #current_date = #date
INSERT #listOfIDs values(#orderid)
END
IF(#name != #current_name)
BEGIN
SET #current_name = #name
SET #current_date = #date
INSERT #listOfIDs values(#orderid)
END
FETCH NEXT FROM Test_Cursor INTO #orderid, #name, #date;
END;
CLOSE Test_Cursor;
DEALLOCATE Test_Cursor;
SELECT * FROM #tmp_SampleData WHERE orderid IN (SELECT orderid FROM #listOfIDs);
Better performing alternatives are very welcome!

select true/false based on col value in a group by

Sorry if the title is not clear. I have a simple table T1
counter int, not null
type nvarchar(250), not null
name nvarchar(50), not null
I'm summing up the counters grouped by type, Like this:
select sum(counter), type
from T1
group by type;
I want to select one more field which is boolean (true/false) which is any of the names contains a specific text i.e. if name like '%Bassem%' then select true. But I can not figure it out since I'm using group by.
Here's a way to do this.
First create a test table and insert some values:
CREATE TABLE dbo.T
(
[counter] int not null,
[type] nvarchar(250) not null,
[name] nvarchar(50) not null
);
INSERT INTO dbo.T ([counter], [type], [name])
VALUES (1, N'Alpha', N'Bassem Akl'),
(2, N'Alpha', N'aaaaa'),
(3, N'Alpha', N'Akl Bassem'),
(4, N'Bravo', N'bbbbb'),
(5, N'Bravo', N'A Bassem'),
(6, N'Charlie', N'ccccc'),
(7, N'Charlie', N'ddddd');
Then use a CTE (common table expression) to determine if the name contains the text you are searching for. You don't have to use a CTE here, but it makes the overall SELECT statement easier to understand.
WITH cte AS
(
SELECT [counter], [type], IIF([name] LIKE N'%Bassem%', 1, 0) AS 'contains'
FROM dbo.T
)
SELECT SUM([counter]) AS 'SumCounter', [type], CAST(MAX([contains]) AS bit) as 'contains'
FROM cte
GROUP BY [type];
Note that Transact-SQL doesn't have a Boolean data type; instead it has a bit type. See Books Online > bit (Transact-SQL) -- https://msdn.microsoft.com/en-gb/library/ms177603.aspx
select sum(counter), type,
max(case when name like '%value%' then true else false end ) as 'Booleanvalue'
from T1
group by type;
you can do this as well,but you may want to do a distinct later using cte or derived table
select sum(counter) over (partition by type order by type),
type,
case when name like '%value%' then true else false end as 'Booleanvalue'
from table
WITH cte as
(
SELECT counter, type, IIF(name like '%Bassem%', 1, 0) as b
FROM #t
)
select sum(counter), type, CAST(max(b) as bit)
from cte
group by type;
A simple CASE statement gets it done.
SELECT SUM(foo.counter)
, type
, CASE WHEN foo.type = 'type a' THEN 1 ELSE 0 END AS true_false
FROM (VALUES (1, 'type a'), (2, 'type b')) AS foo(counter, type)
GROUP BY type;

SQL Server group by count eliminate duplicates [duplicate]

How do I get:
id Name Value
1 A 4
1 B 8
2 C 9
to
id Column
1 A:4, B:8
2 C:9
No CURSOR, WHILE loop, or User-Defined Function needed.
Just need to be creative with FOR XML and PATH.
[Note: This solution only works on SQL 2005 and later. Original question didn't specify the version in use.]
CREATE TABLE #YourTable ([ID] INT, [Name] CHAR(1), [Value] INT)
INSERT INTO #YourTable ([ID],[Name],[Value]) VALUES (1,'A',4)
INSERT INTO #YourTable ([ID],[Name],[Value]) VALUES (1,'B',8)
INSERT INTO #YourTable ([ID],[Name],[Value]) VALUES (2,'C',9)
SELECT
[ID],
STUFF((
SELECT ', ' + [Name] + ':' + CAST([Value] AS VARCHAR(MAX))
FROM #YourTable
WHERE (ID = Results.ID)
FOR XML PATH(''),TYPE).value('(./text())[1]','VARCHAR(MAX)')
,1,2,'') AS NameValues
FROM #YourTable Results
GROUP BY ID
DROP TABLE #YourTable
If it is SQL Server 2017 or SQL Server Vnext, SQL Azure you can use STRING_AGG as below:
SELECT id, STRING_AGG(CONCAT(name, ':', [value]), ', ')
FROM #YourTable
GROUP BY id
using XML path will not perfectly concatenate as you might expect... it will replace "&" with "&" and will also mess with <" and ">
...maybe a few other things, not sure...but you can try this
I came across a workaround for this... you need to replace:
FOR XML PATH('')
)
with:
FOR XML PATH(''),TYPE
).value('(./text())[1]','VARCHAR(MAX)')
...or NVARCHAR(MAX) if thats what youre using.
why the hell doesn't SQL have a concatenate aggregate function? this is a PITA.
I ran into a couple of problems when I tried converting Kevin Fairchild's suggestion to work with strings containing spaces and special XML characters (&, <, >) which were encoded.
The final version of my code (which doesn't answer the original question but may be useful to someone) looks like this:
CREATE TABLE #YourTable ([ID] INT, [Name] VARCHAR(MAX), [Value] INT)
INSERT INTO #YourTable ([ID],[Name],[Value]) VALUES (1,'Oranges & Lemons',4)
INSERT INTO #YourTable ([ID],[Name],[Value]) VALUES (1,'1 < 2',8)
INSERT INTO #YourTable ([ID],[Name],[Value]) VALUES (2,'C',9)
SELECT [ID],
STUFF((
SELECT ', ' + CAST([Name] AS VARCHAR(MAX))
FROM #YourTable WHERE (ID = Results.ID)
FOR XML PATH(''),TYPE
/* Use .value to uncomment XML entities e.g. > < etc*/
).value('.','VARCHAR(MAX)')
,1,2,'') as NameValues
FROM #YourTable Results
GROUP BY ID
DROP TABLE #YourTable
Rather than using a space as a delimiter and replacing all the spaces with commas, it just pre-pends a comma and space to each value then uses STUFF to remove the first two characters.
The XML encoding is taken care of automatically by using the TYPE directive.
Another option using Sql Server 2005 and above
---- test data
declare #t table (OUTPUTID int, SCHME varchar(10), DESCR varchar(10))
insert #t select 1125439 ,'CKT','Approved'
insert #t select 1125439 ,'RENO','Approved'
insert #t select 1134691 ,'CKT','Approved'
insert #t select 1134691 ,'RENO','Approved'
insert #t select 1134691 ,'pn','Approved'
---- actual query
;with cte(outputid,combined,rn)
as
(
select outputid, SCHME + ' ('+DESCR+')', rn=ROW_NUMBER() over (PARTITION by outputid order by schme, descr)
from #t
)
,cte2(outputid,finalstatus,rn)
as
(
select OUTPUTID, convert(varchar(max),combined), 1 from cte where rn=1
union all
select cte2.outputid, convert(varchar(max),cte2.finalstatus+', '+cte.combined), cte2.rn+1
from cte2
inner join cte on cte.OUTPUTID = cte2.outputid and cte.rn=cte2.rn+1
)
select outputid, MAX(finalstatus) from cte2 group by outputid
Install the SQLCLR Aggregates from http://groupconcat.codeplex.com
Then you can write code like this to get the result you asked for:
CREATE TABLE foo
(
id INT,
name CHAR(1),
Value CHAR(1)
);
INSERT INTO dbo.foo
(id, name, Value)
VALUES (1, 'A', '4'),
(1, 'B', '8'),
(2, 'C', '9');
SELECT id,
dbo.GROUP_CONCAT(name + ':' + Value) AS [Column]
FROM dbo.foo
GROUP BY id;
Eight years later... Microsoft SQL Server vNext Database Engine has finally enhanced Transact-SQL to directly support grouped string concatenation. The Community Technical Preview version 1.0 added the STRING_AGG function and CTP 1.1 added the WITHIN GROUP clause for the STRING_AGG function.
Reference: https://msdn.microsoft.com/en-us/library/mt775028.aspx
SQL Server 2005 and later allow you to create your own custom aggregate functions, including for things like concatenation- see the sample at the bottom of the linked article.
This is just an addition to Kevin Fairchild's post (very clever by the way). I would have added it as a comment, but I don't have enough points yet :)
I was using this idea for a view I was working on, however the items I was concatinating contained spaces. So I modified the code slightly to not use spaces as delimiters.
Again thanks for the cool workaround Kevin!
CREATE TABLE #YourTable ( [ID] INT, [Name] CHAR(1), [Value] INT )
INSERT INTO #YourTable ([ID], [Name], [Value]) VALUES (1, 'A', 4)
INSERT INTO #YourTable ([ID], [Name], [Value]) VALUES (1, 'B', 8)
INSERT INTO #YourTable ([ID], [Name], [Value]) VALUES (2, 'C', 9)
SELECT [ID],
REPLACE(REPLACE(REPLACE(
(SELECT [Name] + ':' + CAST([Value] AS VARCHAR(MAX)) as A
FROM #YourTable
WHERE ( ID = Results.ID )
FOR XML PATH (''))
, '</A><A>', ', ')
,'<A>','')
,'</A>','') AS NameValues
FROM #YourTable Results
GROUP BY ID
DROP TABLE #YourTable
An example would be
In Oracle you can use LISTAGG aggregate function.
Original records
name type
------------
name1 type1
name2 type2
name2 type3
Sql
SELECT name, LISTAGG(type, '; ') WITHIN GROUP(ORDER BY name)
FROM table
GROUP BY name
Result in
name type
------------
name1 type1
name2 type2; type3
This kind of question is asked here very often, and the solution is going to depend a lot on the underlying requirements:
https://stackoverflow.com/search?q=sql+pivot
and
https://stackoverflow.com/search?q=sql+concatenate
Typically, there is no SQL-only way to do this without either dynamic sql, a user-defined function, or a cursor.
Just to add to what Cade said, this is usually a front-end display thing and should therefore be handled there. I know that sometimes it's easier to write something 100% in SQL for things like file export or other "SQL only" solutions, but most of the times this concatenation should be handled in your display layer.
Don't need a cursor... a while loop is sufficient.
------------------------------
-- Setup
------------------------------
DECLARE #Source TABLE
(
id int,
Name varchar(30),
Value int
)
DECLARE #Target TABLE
(
id int,
Result varchar(max)
)
INSERT INTO #Source(id, Name, Value) SELECT 1, 'A', 4
INSERT INTO #Source(id, Name, Value) SELECT 1, 'B', 8
INSERT INTO #Source(id, Name, Value) SELECT 2, 'C', 9
------------------------------
-- Technique
------------------------------
INSERT INTO #Target (id)
SELECT id
FROM #Source
GROUP BY id
DECLARE #id int, #Result varchar(max)
SET #id = (SELECT MIN(id) FROM #Target)
WHILE #id is not null
BEGIN
SET #Result = null
SELECT #Result =
CASE
WHEN #Result is null
THEN ''
ELSE #Result + ', '
END + s.Name + ':' + convert(varchar(30),s.Value)
FROM #Source s
WHERE id = #id
UPDATE #Target
SET Result = #Result
WHERE id = #id
SET #id = (SELECT MIN(id) FROM #Target WHERE #id < id)
END
SELECT *
FROM #Target
Let's get very simple:
SELECT stuff(
(
select ', ' + x from (SELECT 'xxx' x union select 'yyyy') tb
FOR XML PATH('')
)
, 1, 2, '')
Replace this line:
select ', ' + x from (SELECT 'xxx' x union select 'yyyy') tb
With your query.
You can improve performance significant the following way if group by contains mostly one item:
SELECT
[ID],
CASE WHEN MAX( [Name]) = MIN( [Name]) THEN
MAX( [Name]) NameValues
ELSE
STUFF((
SELECT ', ' + [Name] + ':' + CAST([Value] AS VARCHAR(MAX))
FROM #YourTable
WHERE (ID = Results.ID)
FOR XML PATH(''),TYPE).value('(./text())[1]','VARCHAR(MAX)')
,1,2,'') AS NameValues
END
FROM #YourTable Results
GROUP BY ID
didn't see any cross apply answers, also no need for xml extraction. Here is a slightly different version of what Kevin Fairchild wrote. It's faster and easier to use in more complex queries:
select T.ID
,MAX(X.cl) NameValues
from #YourTable T
CROSS APPLY
(select STUFF((
SELECT ', ' + [Name] + ':' + CAST([Value] AS VARCHAR(MAX))
FROM #YourTable
WHERE (ID = T.ID)
FOR XML PATH(''))
,1,2,'') [cl]) X
GROUP BY T.ID
Using the Stuff and for xml path operator to concatenate rows to string :Group By two columns -->
CREATE TABLE #YourTable ([ID] INT, [Name] CHAR(1), [Value] INT)
INSERT INTO #YourTable ([ID],[Name],[Value]) VALUES (1,'A',4)
INSERT INTO #YourTable ([ID],[Name],[Value]) VALUES (1,'B',8)
INSERT INTO #YourTable ([ID],[Name],[Value]) VALUES (1,'B',5)
INSERT INTO #YourTable ([ID],[Name],[Value]) VALUES (2,'C',9)
-- retrieve each unique id and name columns and concatonate the values into one column
SELECT
[ID],
STUFF((
SELECT ', ' + [Name] + ':' + CAST([Value] AS VARCHAR(MAX)) -- CONCATONATES EACH APPLICATION : VALUE SET
FROM #YourTable
WHERE (ID = Results.ID and Name = results.[name] )
FOR XML PATH(''),TYPE).value('(./text())[1]','VARCHAR(MAX)')
,1,2,'') AS NameValues
FROM #YourTable Results
GROUP BY ID
SELECT
[ID],[Name] , --these are acting as the group by clause
STUFF((
SELECT ', '+ CAST([Value] AS VARCHAR(MAX)) -- CONCATONATES THE VALUES FOR EACH ID NAME COMBINATION
FROM #YourTable
WHERE (ID = Results.ID and Name = results.[name] )
FOR XML PATH(''),TYPE).value('(./text())[1]','VARCHAR(MAX)')
,1,2,'') AS NameValues
FROM #YourTable Results
GROUP BY ID, name
DROP TABLE #YourTable
Using Replace Function and FOR JSON PATH
SELECT T3.DEPT, REPLACE(REPLACE(T3.ENAME,'{"ENAME":"',''),'"}','') AS ENAME_LIST
FROM (
SELECT DEPT, (SELECT ENAME AS [ENAME]
FROM EMPLOYEE T2
WHERE T2.DEPT=T1.DEPT
FOR JSON PATH,WITHOUT_ARRAY_WRAPPER) ENAME
FROM EMPLOYEE T1
GROUP BY DEPT) T3
For sample data and more ways click here
If you have clr enabled you could use the Group_Concat library from GitHub
Another example without the garbage: ",TYPE).value('(./text())[1]','VARCHAR(MAX)')"
WITH t AS (
SELECT 1 n, 1 g, 1 v
UNION ALL
SELECT 2 n, 1 g, 2 v
UNION ALL
SELECT 3 n, 2 g, 3 v
)
SELECT g
, STUFF (
(
SELECT ', ' + CAST(v AS VARCHAR(MAX))
FROM t sub_t
WHERE sub_t.g = main_t.g
FOR XML PATH('')
)
, 1, 2, ''
) cg
FROM t main_t
GROUP BY g
Input-output is
************************* -> *********************
* n * g * v * * g * cg *
* - * - * - * * - * - *
* 1 * 1 * 1 * * 1 * 1, 2 *
* 2 * 1 * 2 * * 2 * 3 *
* 3 * 2 * 3 * *********************
*************************
I used this approach which may be easier to grasp. Get a root element, then concat to choices any item with the same ID but not the 'official' name
Declare #IdxList as Table(id int, choices varchar(max),AisName varchar(255))
Insert into #IdxLIst(id,choices,AisName)
Select IdxId,''''+Max(Title)+'''',Max(Title) From [dbo].[dta_Alias]
where IdxId is not null group by IdxId
Update #IdxLIst
set choices=choices +','''+Title+''''
From #IdxLIst JOIN [dta_Alias] ON id=IdxId And Title <> AisName
where IdxId is not null
Select * from #IdxList where choices like '%,%'
For all my healthcare folks out there:
SELECT
s.NOTE_ID
,STUFF ((
SELECT
[note_text] + ' '
FROM
HNO_NOTE_TEXT s1
WHERE
(s1.NOTE_ID = s.NOTE_ID)
ORDER BY [line] ASC
FOR XML PATH(''),TYPE).value('(./text())[1]','VARCHAR(MAX)')
,
1,
2,
'') AS NOTE_TEXT_CONCATINATED
FROM
HNO_NOTE_TEXT s
GROUP BY NOTE_ID

Creating contra values in the same column SQL

Aim to write a statement to produce a table with a numeric column that contains contra values, e.g.
Ref Value
a 100
b 75
c 50
c -50
b -75
a -100
I am new to SQL but aware it works row by row, so the only way I could think of doing this is write an initial SELECT statement into a temporary table and INSERT into my temporary table with the contra values, i.e.
SELECT
[Ref],
[Value]
INTO #Temp
FROM
mytable
INSERT INTO #Temp ([Ref], [Value])
SELECT
[Ref],
0 - [Value]
FROM
mytable
While this 'does the job' I fear it is 'messy' (could possibly cause problems when used for its intended purpose) and wondered if anyone would be able to provide a better solution.
Use Union ALL to combine the original and negative values. Then insert into temp table. Try this.
SELECT [Ref],
[Value]
INTO #Temp
FROM (SELECT [Ref],
[Value]
FROM mytable
UNION ALL
SELECT [Ref],
[Value] * -1
FROM mytable) a
If you just want to view the result remove the into #temp table
SELECT [Ref],
[Value]
FROM (SELECT [Ref],
[Value]
FROM mytable
UNION ALL
SELECT [Ref],
[Value] * -1
FROM mytable) a

I need to select data from a table according to time.But my table field is datetime

I need to select data from a table according to time.But my table field is datetime.How can i select data from table only depending on time?Can i use only time in where clause?Please reply
Try this one -
DECLARE #temp TABLE
(
Col1 INT
, Col2 DATETIME
)
INSERT INTO #temp (Col1, Col2)
VALUES
(1, '2013-08-29 07:41:43.717'),
(2, '2013-08-29 08:41:50.067')
SELECT *
FROM #temp
WHERE CAST(Col2 AS TIME) BETWEEN '08:00' AND '12:00'
Output -
Col1 Col2
----------- -----------------------
2 2013-08-29 08:41:50.067
You can try this:
SELECT CONVERT(TIME, column) FROM table
column is your datetime column
You can also use CONVERT(TIME, column) in your WHERE-clause.

Resources