I was wondering if there is a possibility to show full column names when using SELECT * in combination with JOIN.
As an example I have this query (which selects data that gets imported from another application):
SELECT *
FROM Table1 t1
INNER JOIN Table2 t2 ON t1.SomeKey = t2.SomeKey
LEFT JOIN Table3 t3 ON t2.SomeOtherKey = t3.SomeOtherKey
This gives me results like this:
+---------+------+-------+------------+---------+--------------+-----------+------------+--------------+-------+---------------+------------+
| SomeKey | Name | Value | WhateverId | SomeKey | SomeOtherKey | ValueType | CategoryId | SomeOtherKey | Value | ActualValueId | SomeTypeId |
+---------+------+-------+------------+---------+--------------+-----------+------------+--------------+-------+---------------+------------+
| bla | bla | bla | bla | bla | bla | bla | bla | bla | bla | bla | bla |
+---------+------+-------+------------+---------+--------------+-----------+------------+--------------+-------+---------------+------------+
What I'd like to have is the table name in front of each field. The results would be something like this:
+----------------+-------------+-------+------------------+
| Table1.SomeKey | Table1.Name | ..... | Table2.ValueType | .....
+----------------+-------------+-------+------------------+
| bla | bla | ..... | bla | .....
+----------------+-------------+-------+------------------+
I want to do this because the query is already given (without SELECT *) and I now have to find a column in one of the tables with values that match a given identity from an additional table. I know I could analyze each of the tables. However, I'd like to know if there is any simple statement I could add to get the table names in front of the field names.
Well, the answer to that question is NO . You can't alias the columns using the * .
If you want to work around with the columns, specify them your self and alias them as you'd like, in general I try to avoid the use of * to avoid ambiguously columns.
Think about that this way - 2 more minutes of work to avoid a possibilitiy of errors that will take you 100X of it.
You can easily build yourself the SELECT clause using AS for each column. Let's say you have the following tables:
IF OBJECT_ID('dbo.Table01') IS NOT NULL
BEGIN
DROP TABLE Table01;
END;
IF OBJECT_ID('dbo.Table02') IS NOT NULL
BEGIN
DROP TABLE Table02;
END;
CREATE TABLE Table01
(
[ID] INT IDENTITY(1,1)
,[Name] VARCHAR(12)
,[Age] TINYINT
);
CREATE TABLE Table02
(
[ID] INT IDENTITY(1,1)
,[Name] VARCHAR(12)
,[Age] TINYINT
);
and you query is:
SELECT *
FROM Table01
INNER JOIN Table02
ON Table01.[ID] = Table02.[ID];
Just execute the following statement:
SELECT ',' + [source_table] + '.' + [source_column] + ' AS [' + [source_table] + '.' + [source_column] + ']'
FROM sys.dm_exec_describe_first_result_set
(N'SELECT *
FROM Table01
INNER JOIN Table02
ON Table01.[ID] = Table02.[ID]', null,1) ;
You will get this:
Just copy and paste the result to your query (and remove the first comma):
SELECT Table01.ID AS [Table01.ID]
,Table01.Name AS [Table01.Name]
,Table01.Age AS [Table01.Age]
,Table02.ID AS [Table02.ID]
,Table02.Name AS [Table02.Name]
,Table02.Age AS [Table02.Age]
FROM Table01
INNER JOIN Table02
ON Table01.[ID] = Table02.[ID];
and you will get this:
Of course you can play with the output of the function and build the SELECT columns in a way you like (excluding columns, formatting it, etc).
Related
I have a Claims table with 70 columns, 16 of which contain diagnosis codes. The codes mean nothing, so I need to pull the descriptions for each code located in a separate table.
There has to be a simpler way of pulling these code descriptions:
-- This is the claims table
FROM
[database].[schema].[claimtable] AS claim
-- [StagingDB].[schema].[Diagnosis] table where the codes located
-- [ICD10_CODE] column contains the code
LEFT JOIN
[StagingDB].[schema].[Diagnosis] AS diag1 ON claim.[ICDDiag1] = diag1.[ICD10_CODE]
LEFT JOIN
[StagingDB].[schema].[Diagnosis] AS diag2 ON claim.[ICDDiag2] = diag2.[ICD10_CODE]
LEFT JOIN
[StagingDB].[schema].[Diagnosis] AS diag3 ON claim.[ICDDiag3] = diag3.[ICD10_CODE]
-- and so on, up to ....
LEFT JOIN
[StagingDB].[schema].[Diagnosis]AS diag16 ON claim.[ICDDiag16] = diag16.[ICD10_CODE]
-- reported column will be [code_desc]
-- ie:
-- diag1.[code_desc] AS Diagnosis1
-- diag2.[code_desc] AS Diagnosis2
-- diag3.[code_desc] AS Diagnosis3
-- diag4.[code_desc] AS Diagnosis4
-- etc.
I think what you are doing is already correct in given scenario.
Another way can be from programming point of view or you can give try and compare ther performace.
i) Pivot Claim table on those 16 description columns.
ii) Join the Pivoted column with [StagingDB].[schema].[Diagnosis]
Another way can be to put [StagingDB].[schema].[Diagnosis] table in some #temp table
instead of touching large Staging 16 times.
But for data analysis has to be done to decide if there is any way.
You can go for UNPIVOT of the claimTable and then join with Diagnosis table.
TEST SETUP
create table #claimTable(ClaimId INT, Diag1 VARCHAR(10), Diag2 VARCHAR(10))
CREATE table #Diagnosis(code VARCHAR(10), code_Desc VARCHAR(255))
INSERT INTO #ClaimTable
VALUES (1, 'Fever','Cold'), (2, 'Headache','toothache');
INSERT INTO #Diagnosis
VALUEs ('Fever','Fever Desc'), ('cold','cold desc'),('headache','headache desc'),('toothache','toothache desc');
Query to Run
;WITH CTE_Claims AS
(SELECT ClaimId,DiagnosisNumeral, code
FROM #claimTable
UNPIVOT
(
code FOR DiagnosisNumeral in ([Diag1],[Diag2])
) as t
)
SELECT c.ClaimId, c.code, d.code_Desc
FROM CTE_Claims AS c
INNER JOIN #Diagnosis as d
on c.code = d.code
ResultSet
+---------+-----------+----------------+
| ClaimId | code | code_Desc |
+---------+-----------+----------------+
| 1 | Fever | Fever Desc |
| 1 | Cold | cold desc |
| 2 | Headache | headache desc |
| 2 | toothache | toothache desc |
+---------+-----------+----------------+
Can anyone help me to find out the SQL query for following scenario.
I have a search box, which I want to search multiple names separated by spaces.
for example : "David Jones" which gives me the result of David's details and Jones details.
select
emp.cid as empcid,
emp.name,
emp.employeeno,
info.employeeUniqueId,
info.agentId,
info.empBankCode,
info.accountNumber,
info.ibanAccNo
from tblemployee emp,
fk_tblUserEmployeeList f,
empinfo info
where
info.employee = emp.cid
and emp.cid = f.employeeid
and f.userId = 1
and
(
name like '%david%'
or emp.employeeno like '%david%'
or info.employeeUniqueId like '%david%'
or info.agentId like '%david%'
or info.empBankCode like '%david%'
or info.accountNumber like '%david%'
)
I want include Jones inside search box also, then how will the like condition changes>
This seems like a case for full-text search. After setting up full-text indices on your tblemployee, fk_tblUserEmployeeList, and empinfo tables, your query would look something like this:
SELECT
emp.cid AS empcid,
emp.name,
emp.employeeno,
info.employeeUniqueID,
info.agentID,
info.empBankCode,
info.accountNumber,
info.ibanAccNo
FROM dbo.tblemployee emp
INNER JOIN dbo.fk_tblUserEmployeeList f ON
f.employeeid = emp.cid
INNER JOIN dbo.empinfo info ON
info.employee = emp.cid
WHERE
f.userID = 1
AND
( FREETEXT(Emp.*, 'david jones')
OR FREETEXT(info.*, 'david jones')
)
gives you this data:
+--------+-------+------------+------------------+---------+-------------+---------------+-----------+
| empcid | name | employeeno | employeeUniqueID | agentID | empBankCode | accountNumber | ibanAccNo |
+--------+-------+------------+------------------+---------+-------------+---------------+-----------+
| 1 | David | NULL | david | david | david | david | david |
| 2 | Jones | NULL | jones | jones | jones | jones | jones |
+--------+-------+------------+------------------+---------+-------------+---------------+-----------+
Note that I changed your query to use the modern industry-standard join style.
Keep in mind that, to create a full-text index on a table, the table must have a single-column unique index. If one of your tables has a multi-column primary key, you'll have to add a column (see this question for more information).
A couple of notes about your naming conventions:
There's no need to preface table names with tbl (especially since you're not doing so consistently). There are loads of people telling you not to do this: See this answer as an example.
fk_tblUserEmployeeList is a bad table name: The prefixes fk and tbl don't add any information. What kind of information is stored in this table? I would suggest a more descriptive name (with no prefixes).
Now, if you don't want to go the route of using a full-text index, you can parse the input client-side before sending to SQL Server. You can split the search input on a space, and then construct the SQL accordingly.
declare #SearchString varchar(200)='David Jones', #Word varchar(100)
declare #Words table (Word varchar(100))
-- Parse the SearchString to extract all words
while len(#SearchString) > 0 begin
if charindex(' ', #SearchString)>0 begin
select #Word = rtrim(ltrim(substring(#SearchString,0,charindex(' ', #SearchString)))),
#SearchString = rtrim(ltrim(replace(#SearchString, #Word, '')))
end
else begin
select #Word = #SearchString,
#SearchString = ''
end
if #Word != ''
insert into #Words select #Word
end
-- Return Results
select t.*
from MyTable t
join #Words w on
' ' + t.MyColumn + ' ' like '%[^a-z]' + w.Word + '[^a-z]%'
I want to do a simple join of two tables in the same DB.
The expected result is:
To get all Node_ID's From the Table T_Tree that are the same as the TREE_CATEGORY from the Table T_Documents
My T_Documents Tabel:
+--------+----------------+---------------------+
| Doc_ID | TREEE_CATEGORY | Desc |
+--------+----------------+---------------------+
| 89893 | 1363 | Test |
| 89894 | 1364 | with a tab or 4 spa |
+--------+----------------+---------------------+
T_Tree Tabel
+----------+-------+
| Node_ID | Name |
+----------+-------+
| 89893 | Hallo |
| 89894 | BB |
+----------+-------+
Doc_ID is the primary key in the T_Documents Table and Tree_Category is the Foreign key
Node_ID is the primary key in the T_Tree Tabel
SELECT DBName.dbo.T_Tree.NODE_ID
FROM DBName.dbo.T_Documents
inner join TREE_CATEGORY on T_Documents.TREE_CATEGORY = DBName.dbo.T_Tree.NODE_ID
I can not figure it out how to do it correctly .. is this even the right approach ?
You were close. Try this:
SELECT t2.NODE_ID
FROM DBName.dbo.T_Documents t1
INNER JOIN DBName.dbo.T_Tree t2
ON t1.Doc_ID = t2.NODE_ID
Comments:
I used aliases in the query, which are a sort of shorthand for the table names. Aliases can make a query easier to read because it removes the need to always list full table names.
You need to specify table names in the JOIN clause, and the columns used for joining in the ON clause.
Your SQL should be:
SELECT DBName.dbo.T_Tree.NODE_ID
FROM DBName.dbo.T_Documents d
inner join T_Tree t on d.Doc_ID = t.Node_ID
Remember: you join relations (tables), not fields.
Also, for it to work, you need to have common values on Node_ID and Doc_ID fields. That is, for each value in Doc_ID of T_Documents table there must be an equal value in Node_ID field of T_Tree table.
Is it possible to do bulk replace without while loop or what is the best way
Table-1
+-------+--------+
| name | value |
+-------+--------+
| #1# | one |
| #2# | two |
| #3# | three |
+-------+--------+
Table-2 (updated: there is more than one different tokens in table2)
+-----------------------+
| col1 |
+-----------------------+
| string #1# string #2# |
| string #2# string #1# |
| string #3# string #2# |
+-----------------------+
I like to replace all token from Table-2 with Table-1's value column respectively.
Expected Result
+-------------------------+
| col1 |
+-------------------------+
| string one string two |
| string two string one |
| string three string two |
+-------------------------+
Current solution with While loop
declare #table1 table(name nvarchar(50),value nvarchar(50))
insert into #table1 values('#1#','one'),('#2#','two'),('#1#','three')
declare #table2 table(col1 nvarchar(50))
insert into #table2 values('string #1# string #2#'),('string #2# string #1#'),('string #3# string #2#')
WHILE EXISTS (SELECT 1 FROM #table2 t2 INNER JOIN #table1 t1 ON CHARINDEX(t1.name,[col1])>0)
BEGIN
UPDATE #table2
SET col1=REPLACE(col1,name,value)
FROM #table1
WHERE CHARINDEX(name,[col1])>0
END
select * from #table2
Thanks
I suppose you use Sql Server (you've tagged with tsql):
I've run this query on Sql fiddle with 2012 version, but on my PC I've tried with 2008r2 version.
You can procede in this way:
UPDATE table2
SET col1 = REPLACE(col1,
(SELECT name FROM table1 WHERE col1 LIKE '%' + table1.NAME + '%'),
(SELECT value FROM table1 WHERE col1 LIKE '%' + table1.NAME + '%'))
Sql Fiddle
If you want show only the value without UPDATE you can proceed in this way:
SELECT REPLACE(T2.col1, T1.name, T1.value)
FROM table1 T1
JOIN table2 T2
ON T2.col LIKE '%' T1.name + '%'
EDIT
After editing of question / comment my answer is not complete because on the same row can exist more one token. I'm thinking... :)
I thought: :D
IMHO: You must create a loop on your table because the presence of several tokens don't resolve with a single UPDATE statement with subquery, because as you written, the subquery return more than one value.
In Sql Server the REPLACE function change only token, so if you want change in one step two token you must nest your REPLACE function, but we have a number undefined of token in a row so we can't prevent to apply the exact number of REPLACE. An help you can have using a cursor and a dynamic SQL query build on runtime, so you can do a single UPDATE per row. If you want a guide line to use CURSOR and DYNAMIC SQL, please write me. Good night ;)
You can do bulk replacement with this simple piece of code:
update #table2
set col1= left(a.col1,6)+' ' + b.value from #table2 a
join #table1 b on b.name=substring(a.col1,8,3)
select * from #table2
Basically, it updates the column with a new field value.
Suppose I have two tables Main and Other like the following:
Main
+----------+-----------------------------------+
| Field1 | <set of other columns...> |
+----------+-----------------------------------+
| NULL | ... |
| NULL | ... |
| NULL | ... |
Other
+-----------------------------------+
| <same set of other columns...> |
+-----------------------------------+
| ... |
| ... |
| ... |
Is there a concise way to update Main.Field1 where the rest of the columns, taken together, are not in a row of Other?
In other words, I want to update Field1 for each row in
SELECT <set of other columns...> FROM Main
EXCEPT
SELECT <same set of other columns...> FROM Other
Dynamic SQL is an option, but I'm trying to figure out the most efficient way to do something like this.
If you really wanted to you could use the Except clause
UPDATE m
SET field = 'AValue'
FROM
MAIN m
INNER JOIN
(SELECT * FROM MAIN
EXCEPT
SELECT * FROM OTHER ) t
on m.PK = t.PK
DEMO
You should note that the use of * here is very fragile and you should explicitly set your field list. It also assumes that the joining fields (PK) are available in both Main and Other and they would be the same
Other wise you're much better off using NOT EXISTS or an ANTI-JOIN (LEFT/ISNULL)
UPDATE m
SET Field1 = 'foo'
FROM
Main m
LEFT JOIN
Other o
ON m.FIELD2 = o.FIELD2
AND m.FIELD3 = o.FIELD3
WHERE
o.PK is null
DEMO
update m
set ...
from Main m
where not exists(select * from Other where <columns-equal>)
This translates to a left-anti-semi-join.
You could also use a left join but that translates to a normal left-join-plus-filter which is slightly less efficient. This looks like an optimizer weakness.