TSQL - Why sysname is created when I create nVarChar column? - tsql

I have a table in my tsql datatable:
CREATE TABLE dbo.Test
(
Col nVarChar (50) null
)
GO
And then I executed query:
Select
c.name As Name, ty.name as Type, c.max_length As MaxLenght, c.precision As Precision, c.scale As Scale, c.is_nullable As IsNullable, *
From
sys.schemas s
inner join sys.tables t on s.schema_id = t.schema_id
inner join sys.columns c on t.object_id = c.object_id
inner join sys.types ty on ty.system_type_id = c.system_type_id
Where
s.name LIKE 'dbo' AND t.name LIKE 'Test'
The question is... Why there are Two Rows?!

Check this:
SELECT ROW_NUMBER() OVER(PARTITION BY system_type_id ORDER BY system_type_id)
, *
FROM sys.types;
Check the first column for values >1...
There are few types mapping to the same system_type_id. Some names are just an alias for something else...
UPDATE
This question addresses the same issue...

Related

nvarchar vs varchar \ IN vs JOIN

Question regarding "IN" versus "INNER JOIN" and VARCHAR versus NVARCHAR
Examples lay it out...
This query returns the CORRECT results (11 count):
Uses nvarchar(10) data columns for comparison (Id and Location) via INNER JOIN
SELECT b.Location
FROM [configuration].[dbo].[M3_Customer] a
inner join [configuration].[dbo].[M3_WarehouseInventory] b
on a.Id = b.Location
WHERE 1=1
and b.[WarehouseId] = 'NCL'
AND a.[Status] <> '90'
GROUP BY b.[Location], a.Id
This query returns the CORRECT records (11 count):
Uses the same query above as a sub-query, still comparing the same columns but using IN, and adds a forced CONVERT from NVARCHAR to VARCHAR.
SELECT *
FROM [configuration].[dbo].[M3_Customer]
WHERE 1=1
AND convert(varchar(10),[configuration].[dbo].[M3_Customer].[Id]) in (
SELECT convert(varchar(10),b.Location)
FROM [configuration].[dbo].[M3_Customer] a
inner join [configuration].[dbo].[M3_WarehouseInventory] b
on a.Id = b.Location
WHERE 1=1
and b.[WarehouseId] = 'NCL'
AND a.[Status] <> '90'
GROUP BY b.[Location], a.Id
)
This query returns INCORRECT results (10 count):
Only difference between this query and above is the comparison columns are converted to NVARCHAR
SELECT *
FROM [configuration].[dbo].[M3_Customer]
WHERE 1=1
AND convert(nvarchar(10),[configuration].[dbo].[M3_Customer].[Id]) in (
SELECT convert(nvarchar(10),b.Location)
FROM [configuration].[dbo].[M3_Customer] a
inner join [configuration].[dbo].[M3_WarehouseInventory] b
on a.Id = b.Location
WHERE 1=1
and b.[WarehouseId] = 'NCL'
AND a.[Status] <> '90'
GROUP BY b.[Location], a.Id
)
This is the original query that returned INCORRECT results - 10 records, should be returning 11 records:
The issue is associated to the difference between an INNER JOIN and IN - as well as - varchar vs nvarchar
SELECT *
FROM [configuration].[dbo].[M3_Customer]
WHERE 1=1
AND [configuration].[dbo].[M3_Customer].[Id] IN (
SELECT [configuration].[dbo].[M3_WarehouseInventory].[Location]
FROM [configuration].[dbo].[M3_WarehouseInventory]
WHERE 1=1
and [configuration].[dbo].[M3_WarehouseInventory].[WarehouseId] = 'NCL'
GROUP BY [configuration].[dbo].[M3_WarehouseInventory].[Location]
)
AND [configuration].[dbo].[M3_Customer].[Status] <> '90'
The INNER JOIN logic works with nvarchar.
The IN logic works when converting to varchar.
The IN logic using nvarchar failed to return a single record.
We applied LTRIM(RTRIM() to all columns at one point but that did not resolve the issue.
Only using the combination of IN and converting the comparison columns to varchar - resolved the issue.
Why?

Is there a way to join a parameter to a table?

Not sure if this is possible based on what I've researched online. But just want to check to be sure.
If I have a parameter such as:
declare #Person nvarchar(4000)
set #Person = '1234567'
And I have a table called [People], then can I join the two together?
Something like:
SELECT * FROM [People] t1 JOIN #Person t2 ON (t1.ID = t2.ID)
Is such a thing possible and if so can someone please provide the syntax or an exmaple?
Using this sample data:
CREATE TABLE dbo.People (id int, peopleInfo nvarchar(4000));
INSERT dbo.People VALUES (123, 'joe'), (223, 'sally'), (323, 'Mary');
You can do this:
declare #Person nvarchar(4000) = '323'
SELECT t1.*
FROM dbo.People t1
JOIN (VALUES (#Person)) t2(id) ON t1.ID = t2.ID;
But why not just do this?
SELECT t1.*
FROM dbo.People t1
WHERE t1.id = #Person;

How to find all tables where trigger does not exist

The other day we found a table that had a ModifiedDate column but discovered there was no trigger in place to actually update that column. Now I'm trying to write a script to find all of the tables that have a ModifiedDate column but no trigger to update it.
Here is what I have so far:
SELECT so.name AS 'TableName', sc.name AS 'ColumnName', tr.name AS 'Trigger'
FROM sys.objects so
INNER JOIN sys.columns sc ON sc.object_id = so.object_id
LEFT JOIN sys.triggers tr ON so.object_id=tr.object_id
WHERE so.type = 'U' AND sc.name LIKE '%ModifiedDate%'
AND tr.type = 'TR'
To start, I want to find all of the tables that have both the column and trigger. I'm able to find all of the tables with the ModifiedDate column but when I add in that last where filter AND tr.type = 'TR' it returns nothing. I checked and there are tables in there that have both the column and trigger I'm looking for so I would expect to see those on the list.
SELECT so.name AS 'TableName', sc.name AS 'ColumnName', tr.name AS 'Trigger'
FROM sys.objects so
INNER JOIN sys.columns sc ON sc.object_id = so.object_id
LEFT JOIN sys.triggers tr ON so.object_id=tr.parent_id
WHERE so.type = 'U' AND sc.name LIKE '%ModifiedDate%'
AND tr.type = 'TR'
Your join was wrong on Triggers
Cleaning up your query, to find all tables where there are NO triggers where they perhaps should be:
Select t.name As 'TableName'
,c.name As 'ColumnName'
,tr.name As 'Trigger'
From sys.tables t
Join sys.columns c On c.object_id = t.object_id
Left Join sys.triggers tr On t.object_id = tr.parent_id
Where c.name Like '%ModifiedDate%'
And tr.name Is Null
I took out some superfluous stuff. Selecting against tables removes the need to look for Type = 'U' and the parent_id\object_id relationship is such that you don't need to also enforce it with the Type = 'TR' clause.

How to get column names from database?

I'm working with Entity Framework. Is there any method to get the column names of a table from the database?
I want to display all the column names which are in the database.
Not directly from Entity Framework, as far as I know - but you can always execute a standard T-SQL query against the catalog views:
SELECT
ColumnName = c.Name,
SchemaName = s.Name,
TableName = t.Name
FROM
sys.columns c
INNER JOIN
sys.tables t ON c.object_id = t.object_id
INNER JOIN
sys.schemas s ON t.schema_id = s.schema_id
This would give you all columns, along with the schema and table they're part of, from your current SQL Server database.
This query is similar to marc_s's one, but uses sys.objects instead of sys.tables. The system table sys.tables contains many hidden JOIN statements, so this query should be faster -
SELECT
column_name = c.name,
table_name = s.name + '.' + o.name
FROM sys.columns c
JOIN sys.objects o ON c.object_id = o.object_id
JOIN sys.schemas s ON o.schema_id = s.schema_id
WHERE o.type = 'U'

Syntax for SQL Not In List?

I am trying to develop a T-SQL query to exclude all rows from another table "B". This other table "B" has 3 columns comprising its PK for a total of 136 rows. So I want to select all columns from table "A" minus those from table "B". How do I do this? I don't think this query is correct because I am still getting a duplicate record error:
CREATE TABLE #B (STUDENTID VARCHAR(50), MEASUREDATE SMALLDATETIME, MEASUREID VARCHAR(50))
INSERT #B
SELECT studentid, measuredate, measureid
from [J5C_Measures_Sys]
GROUP BY studentid, measuredate, measureid
HAVING COUNT(*) > 1
insert into J5C_MasterMeasures (studentid, measuredate, measureid, rit)
select A.studentid, A.measuredate, B.measurename+' ' +B.LabelName, A.score_14
from [J5C_Measures_Sys] A
join [J5C_ListBoxMeasures_Sys] B on A.MeasureID = B.MeasureID
join sysobjects so on so.name = 'J5C_Measures_Sys' AND so.type = 'u'
join syscolumns sc on so.id = sc.id and sc.name = 'score_14'
join [J5C_MeasureNamesV2_Sys] v on v.Score_field_id = sc.name
where a.score_14 is not null AND B.MEASURENAME IS NOT NULL
and (A.studentid NOT IN (SELECT studentid from #B)
and a.measuredate NOT IN (SELECT measuredate from #B)
and a.measureid NOT IN (SELECT measureid from #B))
use NOT EXISTS...NOT IN doesn't filter out NULLS
insert into J5C_MasterMeasures (studentid, measuredate, measureid, rit)
select A.studentid, A.measuredate, B.measurename+' ' +B.LabelName, A.score_14
from [J5C_Measures_Sys] A
join [J5C_ListBoxMeasures_Sys] B on A.MeasureID = B.MeasureID
join sysobjects so on so.name = 'J5C_Measures_Sys' AND so.type = 'u'
join syscolumns sc on so.id = sc.id and sc.name = 'score_14'
join [J5C_MeasureNamesV2_Sys] v on v.Score_field_id = sc.name
where a.score_14 is not null AND B.MEASURENAME IS NOT NULL
AND NOT EXISTS (select 1 from #B where #b.studentid = A.studentid
and a.measuredate = #B.measuredate
and a.measureid = #B.measureid)
and not exists (select 1 from J5C_MasterMeasures z
where z.studentid = A.studentid)
Just so you know, take a look at Select all rows from one table that don't exist in another table
Basically there are at least 5 ways to select all rows from onr table that are not in another table
NOT IN
NOT EXISTS
LEFT and RIGHT JOIN
OUTER APLY (2005+)
EXCEPT (2005+)
Here is a general solution for the difference operation using left join:
select * from FirstTable
left join SecondTable on FirstTable.ID = SecondTable.ID
where SecondTable.ID is null
Of course yours would have a more complicated join on clause, but the basic operation is the same.
I think you can use "NOT IN" with a subquery, but you say you have a multi-field key?
I'd be thinking about using a left outer join and then testing for null on the right...
Martin.