Query help consolidating two tables - sql

I have two tables (same structure) from two different databases that I'd like to consolidate using a single query if possible.
I'm trying to retrieve all distinct serial numbers and their item name, and two category identifiers. The serial number is stored in 4 fields though. The other problem is the name and category field wont always be the same between the two tables (even though they should be - but that's another issue all together). So, I want the query to return distinct SNs and the name and cat fields from the first table.
So I started with:
SELECT
LEFT(NUMBR_1,4) + '-' + LEFT(NUMBR_2,4) + '-' + LEFT(NUMBR_3,3) + '-' + LEFT(NUMBR_4,5) AS SN
,DESCR
,TYP
,ATNUM
FROM DB1.dbo.table1
UNION
SELECT
LEFT(NUMBR_1,4) + '-' + LEFT(NUMBR_2,4) + '-' + LEFT(NUMBR_3,3) + '-' + LEFT(NUMBR_4,5) AS SN
,DESCR
,TYP
,ATNUM
FROM DB2.dbo.table2
From there I'd manually complete the consolidation in Excel and feed that data into the necessary report. I was hoping to get the final result using just SQL, but doing so is outside of my skill set.
I wrapped the above query in another select to get distinct or group by SN - which gets me the final consolidated list of SN. However, because those values themselves weren't something I could use to then query the other fields from the first table (at least that I could figure out), I wasn't sure how to proceed. Any help would be appreciated. Thanks.

SELECT
LEFT(NUMBR_1,4) + '-' + LEFT(NUMBR_2,4) + '-' + LEFT(NUMBR_3,3) + '-' + LEFT(NUMBR_4,5) AS SN,
,coalesce(t1.DESCR, t2.DESCR) DESCR,
,coalesce(t1.TYP, t2.TYP) TYP
,coalesce(t1.ATNUM, t2.ATNUM) ATNUM
FROM DB1.dbo.table1 t1
FULL JOIN DB2.dbo.table2 t2 ON
t1.NUMBR_1 = t2.NUMBR_1 AND t1.NUMBR_2 = t2.NUMBR_2 AND t1.NUMBR_3 = t2.NUMBR_3 AND t1.NUMBR_4 = t2.NUMBR_4

Similar answer to Joel who beat me to it, though this will actually run. Just swap out #t1 and #t2 for your table names. FULL JOINs return all records from both tables, and where there is no match, returns NULLs for one side and the unmatched values for the other:
declare #t1 table (numbr_1 int
,numbr_2 int
,numbr_3 int
,numbr_4 int
,descr nvarchar(50)
,typ nvarchar(50)
,atnum int
);
declare #t2 table (numbr_1 int
,numbr_2 int
,numbr_3 int
,numbr_4 int
,descr nvarchar(50)
,typ nvarchar(50)
,atnum int
);
insert into #t1 values
(1,1,1,1,'d1','t1',1)
,(1,1,1,2,'d2','t1',1)
,(1,1,1,3,'d3','t2',2)
,(1,1,2,1,'d4','t2',3)
,(1,1,2,2,'d5','t2',4);
insert into #t2 values
(1,1,1,1,'d6','t1',1)
,(1,1,1,2,'d7','t3',1)
,(1,2,1,3,'d8','t4',2)
,(1,2,2,1,'d9','t4',3)
,(1,2,2,2,'d5','t2',4);
select coalesce(left(t1.numbr_1,4) + '-' + left(t1.numbr_2,4) + '-' + left(t1.numbr_3,4) + '-' + left(t1.numbr_4,4)
,left(t2.numbr_1,4) + '-' + left(t2.numbr_2,4) + '-' + left(t2.numbr_3,4) + '-' + left(t2.numbr_4,4)
) as ID
,coalesce(t1.descr,t2.descr) as descr
,coalesce(t1.typ,t2.typ) as typ
,coalesce(t1.atnum,t2.atnum) as atnum
from #t1 t1
full join #t2 t2
on(t1.numbr_1 = t2.numbr_1
and t1.numbr_2 = t2.numbr_2
and t1.numbr_3 = t2.numbr_3
and t1.numbr_4 = t2.numbr_4
);

Related

Displaying all the rows from different columns into one single row and single column in sql

I have a table in a database which consists of name, maths, science, history as the columns wherein the each persons marks are displayed of each subject.
I need to write a query wherein i need to display everything in one single row as:
Anthony:30,70,60 $ Raghav:25,30,45 and so on..
Can anyone tell me how can i do that?
Declare #result Varchar(max)
SELECT #result = COALESCE(#result + '$','')+[name] + ':' + cast(maths as varchar(3)) + ',' + cast(science as varchar(3)) + ',' + cast(history as varchar(3))
FROM tableName
#result variable now contains concatenated string which you can return by
SELECT #result

Using IN clause with CSV cell value to map with a smallint column in another table

I have a table where cells have values stored as CSV (like 2,4,5,6,7). This is basically CSV for months applicable in some criteria, so I have to map those with the actual month ids in my MonthMaster
Let's say my CSV Column's Name in one table is ApplicableMonthIDs having value 3,4,5,6(no spaces in between)
And, I have MonthMaster Table where there are MonthID and MonthNames
MonthID MonthName
3 March
4 April
5 May
6 June
- ---
I have a query where I have to return the values of ApplicableMonthIDs which was 3,4,5,6 as March,April,May,June
Here is what I tried (I have to use this as a sub-query, with multiple joins and cases so, simple would better)
Select Stuff((Select ',' + MonthName from MonthMaster where convert(varchar(10), MonthID) in (Replace(ApplicableMonthIDs ,',',''',''')) for XML Path('')),1,1,'')
Note that ApplicableMonthIDs is a varchar column and MonthID is smallint
try out below script
DECLARE #MonthMaster TABLE ( ID INT PRIMARY KEY, Months
VARCHAR(32) NOT NULL UNIQUE );
DECLARE #MonthsMapping TABLE ( ID INT PRIMARY KEY, Name
NVARCHAR(64) NOT NULL, ApplicableMonthIDs VARCHAR(255) NOT NULL );
INSERT #MonthMaster VALUES (1,'jan'), (2,'feb'), (3,'march');
INSERT #MonthsMapping VALUES (1,'aa','2,1'), (2,'bbb','1'),
(3,'ccc','1,3'), (4,'dd','2,3,1');
SELECT ID, Name, ApplicableMonthIDs = STUFF((SELECT ',' + d.Months
FROM #MonthMaster AS d
INNER JOIN #MonthsMapping AS ei
ON ',' + ei.ApplicableMonthIDs + ',' LIKE '%,' + CONVERT(VARCHAR(12), d.id) + ',%'
WHERE ei.ID = e.ID
ORDER BY d.id
FOR XML PATH, TYPE).value('.[1]', 'nvarchar(max)'), 1, 1, '') FROM #MonthsMapping AS e ORDER >BY ID;
I think this will help you
Try out below query..
declare #ApplicableMonthIDs varchar(50) set #ApplicableMonthIDs
='2,3,4,7'
EXEC (' SELECT * FROM [dbo].[MonthMaster] WHERE CONVERT(VARCHAR(50),MonthID) IN
( ' + #ApplicableMonthIDs + ' ) ') GO
the above query is faster as it used a Clustered Index Seek only.

Get the value of a column replacing the comma separator

How can I get each value of a column that has a comma separator in her value ?
Example:
ID ColumnUnified
1 12,34,56,78
2 80,99,70,56
What I want is a query to get the number without comma. If possible, in collumns.
12 34 56 78
This will work for any number of values http://beyondrelational.com/modules/2/blogs/70/posts/10844/splitting-delimited-data-to-columns-set-based-approach.aspx
The solution Madhivanan's link refers to is very creative, but I had a slight problem with it on SQL Server 2012 related to the name of one of the columns (Start). I've modified the code in his answer to use StartPos instead of Start for the column name.
I was not familiar with the system procedure spt_values, but I found a very informative description of the procedure here on SO for those who are interested in exactly how this solution works.
Finally, here's the (slightly) revised code from Madhivana's answer:
CREATE TABLE #test(id int, data varchar(100))
INSERT INTO #test VALUES (1,'This,is,a,test,string')
INSERT INTO #test VALUES (2,'See,if,it,can,be,split,into,many,columns')
DECLARE #pivot varchar(8000)
DECLARE #select varchar(8000)
SELECT #pivot = COALESCE(#pivot + ',', '') + '[col'
+ CAST(number + 1 AS VARCHAR(10)) + ']'
FROM master..spt_values
WHERE type = 'p'
AND number <= ( SELECT MAX(LEN(data) - LEN(REPLACE(data, ',', '')))
FROM #test
)
SELECT #select = '
select p.*
from (
select
id,substring(data, StartPos+2, endPos-StartPos-2) as token,
''col''+cast(row_number() over(partition by id order by StartPos) as varchar(10)) as n
from (
select
id, data, n as StartPos, charindex('','',data,n+2) endPos
from (select number as n from master..spt_values where type=''p'') num
cross join
(
select
id, '','' + data +'','' as data
from
#test
) m
where n < len(data)-1
and substring(data,n+1,1) = '','') as data
) pvt
Pivot ( max(token)for n in (' + #pivot + '))p'
EXEC(#select)
DROP TABLE #test

Find special characters in all rows in specific columns in table

I have a database containing about 50 tables, each table has about 10-100 columns with max 1 milion rows in each table. (quite big like for a newbie :P)
Database is old and some rows contains special characters (invisible characters or some weird unicode) and I would like to remove those characters.
I was searching google and I found a small snippet that lists all columns with specific type:
SELECT
OBJECT_NAME(col.OBJECT_ID) AS [TableName]
,col.[name] AS [ColName]
,typ.[name] AS [TypeName]
FROM
sys.all_columns col
INNER JOIN sys.types typ
ON col.user_type_id = typ.user_type_id
WHERE
col.user_type_id IN (167,231)
AND
OBJECT_NAME(col.OBJECT_ID) = 'Orders'
This lists all columns that are varchar or nvarchar.
I found two functions, one that returns a table of all characters from a string and second that checks if string contains any special characters:
CREATE FUNCTION AllCharactersInString (#str nvarchar(max))
RETURNS TABLE
AS
RETURN
(SELECT
substring(B.main_string,C.int_seq,1) AS character
,Unicode(substring(B.main_string,C.int_seq,1)) AS unicode_value
FROM
(SELECT
#str AS main_string) B,(SELECT
A.int_seq
FROM
(SELECT
row_number() OVER (ORDER BY name) AS int_seq
FROM
sys.all_objects) A
WHERE
A.int_seq <= len(#str)) C
)
And second:
CREATE FUNCTION ContainsInvisibleCharacter (#str nvarchar(max))
RETURNS int
AS
BEGIN
DECLARE #Result Int
IF exists
(SELECT
*
FROM
AllCharactersInString(#str)
WHERE
unicode_value IN (1,9,10,11,12,13,14,28,29,31,129,141,143,144,157,160))
BEGIN SET #Result = 1
END
ELSE
BEGIN SET #Result = 0
END
RETURN #Result
END
My question is how to combine thos two functions into one (if it is possible and if it will be faster) and second: how to run that function on all records in all columns (that are specific type) in a table.
I have this code:
SELECT
O.Order_Id
,Rn_Descriptor
FROM
dbo.Order O
WHERE
dbo.ContainsInvisibleCharacter(O.Rn_Descriptor) = 1
AND
O.Order_Id IN (SELECT TOP 1000
Order.Order_Id
FROM
dbo.Order
WHERE
Order.Rn_Descriptor IS NOT NULL
)
But it works sooo slow :/
Mayby there is a fastest way to remove unwanted characters?
What will be fine is to find rows containing those characters, list them, then I could manually check them.
You can do this more efficiently using LIKE.
CREATE FUNCTION ContainsInvisibleCharacter(#str nvarchar(max)) RETURNS int
AS
BEGIN
RETURN
(SELECT CASE WHEN #str LIKE
'%[' + NCHAR(1) + NCHAR(9) + NCHAR(10) + NCHAR(11) + NCHAR(12)
+ NCHAR(13) + NCHAR(14) + NCHAR(28) + NCHAR(29) + NCHAR(31)
+ NCHAR(129) + NCHAR(141) + NCHAR(143) + NCHAR(144)
+ NCHAR(157) + NCHAR(160) + ']%'
THEN 1 ELSE 0 END)
END

SQL - Move multiple rows worth of data to one row

What I am trying to do is take multiple rows of data from a column and insert it into a single cell. Here's what I have below:
+++HouseNumber+++++++CustomerType+++
+ 1 + Residential +
+ 2 + Commercial +
+ 2 + Residential +
+ 3 + Residential +
++++++++++++++++++++++++++++++++++++
And I need to get this to something that looks like this:
+++HouseNumber+++++++CustomerType+++++++++++++++
+ 1 + Residential +
+ 2 + Commercial Residential +
+ 3 + Residential +
++++++++++++++++++++++++++++++++++++++++++++++++
I realize that this is against the normalization thing; however, I simply need this data displayed this way so that I can view it more easily later on, the particular cell will never again be referenced for any individual item within it.
I tried to do this by creating two tables, one with a tempCustomerType, and one with a a customerType field orignally NULL and then update using the following:
UPDATE CustomerIdentifier
SET CustomerIdentifier.CustomerType = TempTable2.CustomerTypeTemp + CustomerIdentifier.CustomerType
FROM CustomerIdentifier
INNER JOIN TempTable2
ON CustomerIdentifier.SUB_ACCT_NO_OCI = TempTable2.SUB_ACCT_NO_OCI
However, after that each field was still null. So, any chance anyone here can help me? Thanks!
Also, if there is a way to do this without creating a second table, that would be great as well.
NULL + 1 in T/SQL always will return null;
The solutions for you problem are described here
We implemented our own CLR aggregate function as described here, you can then write:
DECLARE #test TABLE (
HouseNumber INT,
CustomerType VARCHAR(16)
)
INSERT INTO #test
SELECT 1, 'Residential'
UNION SELECT 2, 'Commercial'
UNION SELECT 2, 'Residential'
UNION SELECT 3, 'Residential'
SELECT HouseNumber, dbo.Concatenate(CustomerType)
FROM #test
GROUP BY HouseNumber
Below a simpler solution to the problem. Unfortunately untested on my machine (sql server install borked), I will test tomorrow and edit the answer if necessary.
This will work with SQL 2005 and above and doesn't require any UDFs or CLR. It is also pretty fast too.
/* Test Table & Data */
DECLARE #TestTable TABLE
(
HouseNumber int,
CustomerType varchar(12)
)
;
INSERT #TestTable
SELECT 1, 'Residential' UNION ALL
SELECT 2, 'Commercial' UNION ALL
SELECT 2, 'Residential' UNION ALL
SELECT 3, 'Residential' UNION ALL
;
/* CTE to construct the concatenated data. */
WITH ConcatData (HouseNumber,CustomerType) as
(
SELECT HouseNumber,STUFF((SELECT ', ' + CustomerType
FROM #TestTable TT2
FOR XML PATH ('')
WHERE TT2.HouseNumber = TT1.HouseNumber),1,2,'')
FROM TestTable TT1
GROUP BY TT1.HouseNumber
)
/* Update the test table using the concatenated data from the CTE - joining on HouseNumber */
UPDATE trg
SET CustomerType = src.CustomerType
FROM #TestTable trg
INNER JOIN ConcatData src on src.HouseNumber = trg.HouseNumber