Select one column data in different columns in SQL Server - sql

I have to match two tables, table1 and table2, for one row of table1 I have two or more rows in table 2 and I want to display them in one row.
Now I have the following:
Select
a.[ID], b.[Description]
From
table1 a, table2 b
Where
a.[ID] = b.[ID];
Output:
[ID] | [Description]
-----+--------------
1 | Fee
1 | Domestic Fee
2 | Fee
2 | International Fee
I want to get the following result
[ID] | [Description1] | [Description2]
-----+----------------+---------------
1 | Fee | Domestic Fee
2 | Fee | International Fee
Thank you in advance :)

If you have multiple descriptions then you can use Pivot as below:
Select * from (
Select *, RowN = Concat('Description', Row_Number() over (partition by Id order by Id)) from #description ) a
pivot (max([Description]) for RowN in ([Description1],[Description2])) p
Output as below:
+----+--------------+-------------------+
| Id | Description1 | Description2 |
+----+--------------+-------------------+
| 1 | Fee | Domestic Fee |
| 2 | Fee | International Fee |
+----+--------------+-------------------+

This is my proposal with cross apply operator
data prepartaion:
create table tst_1 (id int, dsc nvarchar(30))
insert into tst_1 (id, dsc)
values (1,'Fee'),(1,'Domestic Fee'),(2,'Fee'),(2,'International Fee')
Next simple select with jon show data that you looking for:
select t1.id, t1.dsc, x.dsc
from tst_1 t1
cross apply ( select row_number() over (order by id) as lp
,id
,dsc
from tst_1 )x
where x.id = t1.id and x.dsc <> t1.dsc
and lp%2 = 0
tst_1 can be a view based on select ... from you question.

Select
a.[ID],a.[Description], b.[Description]
From
table1 a left outer join table2 b
on
a.[ID] = b.[ID];``

try this:
select ID, DESCRIPTION1, DESCRIPTION2
from
(
Select a.[ID]
,b.[Description]
,'DESCRIPTION' + CAST(ROW_NUMBER() OVER(PARTITION BY a.ID ORDER BY a.ID) AS VARCHAR(255))AS RN
from table1 a
JOIN table2 b ON a.[ID] = b.[ID]
) d
pivot
(
max([Description])
for RN in (DESCRIPTION1,DESCRIPTION2)
) piv;

Related

How to find duplicate row when any one word of desc column matching within group

I have a result like this:
I need to update "flag" column as duplicate when any one word from the row matches with second row within group of "mfgid" column.
--test dataset
declare #table as table
(id int,
mfgid int,
[desc] varchar(100))
insert into #table
values (1,111,'abc xyz pqr'),
(2,111,'abc tyu fgh'),
(3,222,'abc pqr'),
(4,222,'lmn stu'),
(5,333,'pqr spd hki abc'),
(6,333,'lmn jsk pqr klo')
How can I do this?
Here is a possible solution
WITH K AS
(
SELECT mfgid,
value,
count(*) over ( partition by mfgid, value order by mfgid) Dups
FROM #Table cross apply STRING_SPLIT([desc], ' ')
)
SELECT T.*,
IIF(
EXISTS(SELECT 1 FROM K WHERE K.mfgid = T.mfgid AND K.Dups > 1),
'Duplicte',
''
) Flag
FROM #Table T;
Results:
+----+-------+-----------------+----------+
| id | mfgid | desc | Flag |
+----+-------+-----------------+----------+
| 1 | 111 | abc xyz pqr | Duplicte |
| 2 | 111 | abc tyu fgh | Duplicte |
| 3 | 222 | abc pqr | |
| 4 | 222 | lmn stu | |
| 5 | 333 | pqr spd hki abc | Duplicte |
| 6 | 333 | lmn jsk pqr klo | Duplicte |
+----+-------+-----------------+----------+
Demo
two possible solutions below:
--test dataset
declare #table as table
(id int,
mfgid int,
[desc] varchar(100))
insert into #table
values (1,111,'abc xyz pqr'),
(2,111,'abc tyu fgh'),
(3,222,'abc pqr'),
(4,222,'lmn stu'),
(5,333,'pqr spd hki abc'),
(6,333,'lmn jsk pqr klo')
Solution 1:
If you have only 4 words in string (based on your screenshot)
;with cte2 as
(select *
from (select id,
mfgid,
parsename(replace(s.[desc],' ','.'),1) as [a1],
parsename(replace(s.[desc],' ','.'),2) as [a2],
parsename(replace(s.[desc],' ','.'),3) as [a3],
parsename(replace(s.[desc],' ','.'),4) as [a4]
from #table as s) as a
unpivot (testval FOR val IN (a1, a2, a3, a4)) unpvt
)
select m.id, m.mfgid, m.[desc], t.flag
from #table as m
outer apply
(select top (1) 'duplicate' as flag
from cte2 as a
join cte2 as b
on a.mfgid = b.mfgid
and a.id != b.id
and a.testval = b.testval
and m.mfgid = a.mfgid) as t
test is here
Solution 2:
If you have more that 4 words in string
;with cte as
( select t.*, s.[value]
from #table as t
cross apply
(select ltrim(rtrim(split.a.value('.','varchar(100)'))) as [value]
from (select cast('<M>'+replace([desc],' ','</M><M>')+'</M>' as xml) as data) as a
cross apply data.nodes ('/M') as split(a)
) as s
)
select m.id, m.mfgid, m.[desc], t.flag
from #table as m
outer apply
(select top (1) 'duplicate' as flag
from cte as a
join cte as b
on a.mfgid = b.mfgid
and a.id != b.id
and a.Value = b.Value
and m.mfgid = a.mfgid) as t
test is here
This assumes the OP is using SQL Server 2016+, as they haven't let us know the version:
WITH Split AS(
SELECT T.id,
T.mfgid,
T.[desc],
SS.[value]
FROM #table T
CROSS APPLY STRING_SPLIT([desc],' ') SS)
SELECT S.id,
S.mfgid,
S.[desc],
CASE MAX(Dups) WHEN 0 THEN NULL ELSE 'Duplicate' END AS Flag
FROM Split S
CROSS APPLY (SELECT COUNT(*) AS [Dups]
FROM Split ca
WHERE ca.mfgid = S.mfgid
AND ca.[value] = S.[value]
AND ca.id != S.id) C
GROUP BY S.id,
S.mfgid,
S.[desc];

Select item that is different in each of group by a column

I have this sample table
+--------+-------------+
| DBName | Description |
+--------+-------------+
| A | Car |
| A | Boat |
| B | Car |
| B | Plane |
| C | Car |
| C | Boat |
| C | Plane |
+--------+-------------+
I want to take only Description that is not exist on every DBName and show what DBName that don't have the Description.
The Result from the query that I want
+--------+-------------+
| DBName | Description |
+--------+-------------+
| A | Plane |
| B | Boat |
+--------+-------------+
Keep in mind it will be more than just A,B,C on DBName.
Interesting issue. Here are a couple of options for solving. There's discussions around these techniques here, along with a few suggestions of other routes for handling scenarios such as this.
SQL Fiddle Example
select DBName, Description
from (
select DBName, Description
from (select distinct DBName from demo) a
cross join (select distinct Description from demo) b
) c
except
select DbName, Description from demo
This solution works by fetching every possible combination (via cross join of distinct values for each column), then excluding all those which already exist via the except clause.
SQL Fiddle Example
select [each].DBName, missing.Description
from (select distinct DBName from demo) [each]
cross join (select distinct Description from demo) [missing]
where not exists
(
select top 1 1
from demo [exists]
where [exists].DbName = [each].DBName
and [exists].Description = [missing].Description
)
This solution is the same as the above, only instead of the except cluase we use where not exists to remove existing combos.
Ideally you should have a master list of data. In case you do not you should deriv3 it from the data and then put checks against them like below:
SQL Fiddle Example
select
masterlistDbname.Dbname,
masterlistDesc.Description
from
(
select distinct Description from yourtable
) masterlistDesc
cross join
(
select distinct Dbname from yourtable
) masterlistDbname
left join
yourtable t1
on t1.Dbname = masterlistDbname.Dbname
and t1.Description = masterlistDesc.Description
where t1.Dbname is NULL
use NOT EXISTS
SELECT *
FROM yourtable t
WHERE NOT EXISTS
(
SELECT *
FROM yourtable x
WHERE x.Description = t.Description
AND x.DBName <> t.DBName
)
you should throw little more Sample data.
Try this,
create table #test(DBName varchar(50),Descriptions varchar(50) )
insert into #test VALUES
('A','Car')
,('A','Boat')
,('B','Car')
,('B','Plane')
,('C','Car')
,('C','Boat')
,('C','Plane')
;
WITH CTE
AS (
SELECT *
,ROW_NUMBER() OVER (
ORDER BY (
SELECT NULL
)
) rn
,ROW_NUMBER() OVER (
PARTITION BY DBName ORDER BY (
SELECT NULL
)
) rn1
FROM #test
)
SELECT t.DBName
,t1.Descriptions
FROM cte t
CROSS APPLY (
SELECT TOP 1 Descriptions
FROM cte t1
WHERE t1.rn > t.rn
AND t.Descriptions <> t1.Descriptions
AND t.dbname <> t1.dbname
ORDER BY t1.rn
) t1
WHERE t.rn1 = 1
drop table #test

Two rows with the same id and two different values, getting the second value into another column

I have two rows with the same id but different values. I want a query to get the second value and display it in the first row.
There are only two rows for each productId and 2 different values.
I've tried looking for this for the solution everywhere.
What I have, example:
+-----+-------+
| ID | Value |
+-----+-------+
| 123 | 1 |
| 123 | 2 |
+-----+-------+
What I want
+------+-------+---------+
| ID | Value | Value 1 |
+------+-------+---------+
| 123 | 1 | 2 |
+------+-------+---------+
Not sure whether order matters to you. Here is one way:
SELECT MIN(Value), MAX(Value), ID
FROM Table
GROUP BY ID;
This is a self-join:
SELECT a.ID, a.Value, b.Value
FROM table a
JOIN table b on a.ID = b.ID
and a.Value <> b.Value
You can use a LEFT JOIN instead if there are IDs that only have one value and would be lost by the above JOIN
May be you may try this
DECLARE #T TABLE
(
Id INT,
Val INT
)
INSERT INTO #T
VALUES(123,1),(123,2),
(456,1),(789,1),(789,2)
;WITH CTE
AS
(
SELECT
RN = ROW_NUMBER() OVER(PARTITION BY Id ORDER BY Val),
*
FROM #T
)
SELECT
*
FROM CTE
PIVOT
(
MAX(Val)
FOR
RN IN
(
[1],[2]--Add More Numbers here if there are more values
)
)Q

How to get Order numbers where collection number has a top and a corresponding bottom?

This is how the main order table looks :-
| Order_num | Collection_Num |
+--------------+----------------+
| 20143045585 | 123456 |
| 20143045585 | 789012 |
| 20143045585 | 456897 |
| 20143758257 | 546465 |
+--------------+----------------+
These are the collections:-
| tops | bottom |
+--------------+----------------+
| 353735 | 745758 |
| 123456 | 789012 |
| 456456 | 456897 |
| 323456 | 546465 |
+--------------+----------------+
Desired Output:-
| Order_num |
+--------------+
| 20143045585 |
Here Order number 20143045585 has both a top and a bottom from the same row in table number 2 (each row in 2nd table forms a particular combination called 'A Collection' i.e. 1 top and corresponding bottom ).
What I want to know -
All the order numbers which have a top and a corresponding bottom in 'Collection_num' column.
Can anyone help me with a SQL code for this ?
Let me know if any of this is unclear.
select Order_num
From table_1 as A
where exists
(select tops from table_2 as B where B.tops = A.Collection_num)
AND
(select bottom from table2 as B where B.bottom = A.Collection_num)
I am assuming you just have the first table of data and each order can only have the two relevant collections or less. Perhaps:
select T1.Order_Num
,T1.Collection_Num AS Tops
,T2.Collection_Num AS Bottom
from Table1 T1
inner join Table1 T2
on T1.Order_Num = T2.Order_Num
and T1.Collection_Num < T2.Collection_Num
order by T1.Order_Num
You can try using subquery
select distinct order_num from #yourorder where collection_num
in (select tops from #yourcollections)
and order_num in
( select order_num from #yourorder where collection_num in
(select bottom from #yourcollections) )
Pretty sure that something like this should work for you. I am just using the ctes here to create the test data so it can be queried.
with Orders (OrderNum, CollectionNum) as
(
select 20143045585, 123456 union all
select 20143045585, 789012 union all
select 20143045585, 456897 union all
select 20143758257, 546465
)
, Collections (CollectionID, tops, bottoms) as
(
select 1, 353735, 745758 union all
select 2, 123456, 789012 union all
select 3, 456456, 456897 union all
select 4, 323456, 546465
)
select o.OrderNum
, t.tops
, b.bottoms
from Orders o
join Collections t on t.tops = o.CollectionNum
join
(
select o.OrderNum
, b.bottoms
, b.CollectionID
from Orders o
join Collections b on b.bottoms = o.CollectionNum
) b on b.CollectionID = t.CollectionID
Here is the query that I used:
Select *
From (select A.Order_num, B.Coll_ID, B.Bottoms from Orders_table as A
Join Collections_Table as B
on A.Collection_num = B.Bottoms
) as C
join
(select K.Order_num, M.Coll_ID, M.Tops from Orders_table as K
Join Collections_Table as M
on A.Collection_num = B.Tops
) as D
on C.Orders_B = D.Orders_Num AND C.Coll_ID = D.Coll_ID
)

MSSQL: Only last entry in GROUP BY (with id)

Following / copying computhomas's question, but adding some twists...
I have the following table in MSSQL2008
id | business_key | result | date
1 | 1 | 0 | 9
2 | 1 | 1 | 8
3 | 2 | 1 | 7
4 | 3 | n | 6
5 | 4 | 1 | 5
6 | 4 | 0 | 4
And now i want to group based on the business_key returning the complete entry with the newest date.
So my expected result is:
id | business_key | result | date
1 | 1 | 0 | 9
3 | 2 | 1 | 7
4 | 3 | n | 6
5 | 4 | 1 | 5
I also bet that there is a way to achieve that, i just can't find / see / think of it at the moment.
edit: sorry about this, I actually meant something else from original question I did. I felt like editing this might be better than accepting a solution and making another question. my original problem was that I am not filtering by id.
SELECT t.*
FROM
(
SELECT *, ROW_NUMBER() OVER
(
PARTITION BY [business_key]
ORDER BY [date] DESC
) AS [RowNum]
FROM yourTable
) AS t
WHERE t.[RowNum] = 1
SELECT
*
FROM
mytable
WHERE
ID IN (SELECT MAX(ID) FROM mytable GROUP BY business_key)
SELECT
MAX(T1.id) AS [id],
T1.business_key,
T1.result
FROM
dbo.My_Table T1
LEFT OUTER JOIN dbo.My_Table T2 ON
T2.business_key = T1.business_key AND
T2.id > T1.id
WHERE
T2.id IS NULL
GROUP BY T1.business_key,
T1.result
ORDER BY MAX(T1.id)
Edited based on clarifications
SELECT M1.*
FROM My_Table M1
INNER JOIN
(
SELECT [business_key], MAX([date]) as MaxDate
FROM My_Table
GROUP BY [business_key]
) M2 ON M1.business_key = M2.business_key AND M1.[date] = M2.MaxDate
ORDER BY M1.[id]
Assuming the combination of business_key & date is unique then....
Working example (3rd time is a charm):
declare #src as table(id int, business_key int,result int,[date] int)
insert into #src
SELECT 1,1,0,9
UNION SELECT 2,1,1,8
UNION SELECT 3,2,1,7
UNION SELECT 4,3,1,6
UNION SELECT 5,4,1,5
UNION SELECT 6,4,0,4
;with bkdate(business_key,[date])
AS
(
select business_key,MAX([date])
from #src
group by business_key
)
select src.* from #src src
inner join bkdate
ON src.[date] = bkdate.date
and src.business_key = bkdate.business_key
order by id
How about (edited after question change):
with latestdate as (
select business_key, maxdate=max(date)
from the_table
group by business_key
), latest as (
select ID = max(id)
from the_table
inner join latestdate
on the_table.business_key=latestdate.business_key
and the_table.date=latestdate.maxdate
group by the_table.business_key
)
select the_table.*
from the_table
inner join latest
on latest.id=the_table.id