So, I'm trying to build a code generator that will extract indexes from a database and make a class that will filter based on an index.
Below code works in SQL-server and yields 2 records. But my SqlDataReader yields zero records.
Provided example for 1 table with index.
Hoping someone can help me out here.
Code in SQL server:
create table Agent(
ID bigint constraint PK_Agent primary key identity(1,1),
LastName nvarchar(50) not null,
FirstName nvarchar(50) not null,
index IN_Agent_Name nonclustered (LastName, FirstName)
)
select t.object_id,
s.name as schemaname,
t.name as tablename,
i.index_id,
i.name as indexname,
index_column_id,
c.name as columnname
from sys.tables t
inner join sys.schemas s on t.schema_id = s.schema_id
inner join sys.indexes i on i.object_id = t.object_id
inner join sys.index_columns ic on ic.object_id = t.object_id and ic.index_id = i.index_id
inner join sys.columns c on c.object_id = t.object_id and ic.column_id = c.column_id
where i.index_id > 0
and i.type in (1, 2)
and i.is_primary_key = 0
and i.is_unique_constraint = 0
and i.is_disabled = 0
and i.is_hypothetical = 0
and ic.key_ordinal > 0
and t.name like 'Agent'
and i.name like 'IN_Agent_Name'
Code in VS:
public static TableIndex GetIndex(string indexName, string tableName)
{
TableIndex index = null;
using (var conn = new SqlConnection("Server=localhost;Database=VenturaERD;User Id=VenturaDBUser;Password = Ventura;"))
{
conn.Open();
var cmd = new SqlCommand("select t.object_id, s.name as schemaname, t.name as tablename, i.index_id, i.name as indexname, index_column_id, c.name as columnname from sys.tables t inner join sys.schemas s on t.schema_id = s.schema_id inner join sys.indexes i on i.object_id = t.object_id inner join sys.index_columns ic on ic.object_id = t.object_id and ic.index_id = i.index_id inner join sys.columns c on c.object_id = t.object_id and ic.column_id = c.column_id where i.index_id > 0 and i.type in (1, 2) and i.is_primary_key = 0 and i.is_unique_constraint = 0 and i.is_disabled = 0 and i.is_hypothetical = 0 and ic.key_ordinal > 0 and t.name like '" + tableName + "' and i.name like '" + indexName + "'")
{
Connection = conn
};
using (var reader = cmd.ExecuteReader())
{
if (reader.Read())
{
index = new TableIndex()
{
TableId = reader.GetInt32(reader.GetOrdinal("object_id")),
TableName = reader.GetString(reader.GetOrdinal("tablename")),
IndexId = reader.GetInt32(reader.GetOrdinal("index_id")),
IndexName = reader.GetString(reader.GetOrdinal("indexname")),
Columns = new List()
{
new IndexColumn()
{
ColumnName = reader.GetString(reader.GetOrdinal("columnname")),
Order=reader.GetInt32(reader.GetOrdinal("index_column_id"))
}
}
};
while (reader.Read())
{
index.Columns.Add(new IndexColumn()
{
ColumnName = reader.GetString(reader.GetOrdinal("columnname")),
Order = reader.GetInt32(reader.GetOrdinal("index_column_id"))
});
}
}
reader.Close();
}
}
return index;
}
Please check the users rights, I believe with only the public rights the user will not get any data.
Make sure the user you are connecting to with SQL management studio and the user in the connection string are the same.
The user (in my tests at least) needs at least the db_datareader role.
Related
How does a SQL Server query select from parameter? I just want to make it simple set select column based on my C# code. Is it possible?
Here is my stored procedure:
ALTER PROCEDURE [dbo].[GetMembersDetailGenerateChanceTop10000]
#EventId nvarchar(255),
#PeriodId nvarchar(255),
#QueryParam nvarchar(1000)
AS
BEGIN
SET NOCOUNT ON;
SELECT DISTINCT TOP 10000 #QueryParam
FROM ign..Chance_Generated cg
INNER JOIN ign..Contact c ON cg.ContactID = c.ContactId
LEFT JOIN ign..CustomerAddress ca ON ca.parentid = cg.contactid
LEFT JOIN ign..new_cardlevelconfig cl ON cl.new_cardlevelconfigid = c.new_cardlevel
LEFT JOIN ign..new_country co ON co.new_countryid = c.new_country
LEFT JOIN ign..new_province po ON po.new_provinceId = c.new_Province
LEFT JOIN ign..StringMap sm ON sm.AttributeValue = c.new_IDType
LEFT JOIN ign..new_city cy ON cy.new_cityId = c.new_CityCounty
LEFT JOIN ign..new_transactionheader th ON cg.New_Name COLLATE DATABASE_DEFAULT = th.new_name COLLATE DATABASE_DEFAULT
WHERE cg.EventId = #EventId
AND (ca.AddressNumber = '1' OR ca.AddressNumber IS NULL)
AND (sm.AttributeName IS NULL OR sm.AttributeName = 'new_idtype')
AND cg.periodId = #PeriodId
QueryParam, EventId, PeriodId will be filled from C# code.
Here is my C# code:
private List<GenerateModel> getDataTopFromStoreProcedure(string EventId, string PeriodId)
{
// query select parameter
string QueryParam = #"cg.Chance_Number, th.new_name as [th name], dateadd(HOUR,7,th.createdon) as [th createdon],
c.new_Initial, c.FirstName, c.LastName";
string ConnString = GenerateChance.Properties.Settings.Default["DB_ConnectionString"].ToString();
using (SqlConnection conn = new SqlConnection(ConnString))
{
SqlCommand cmd = new SqlCommand();
cmd.CommandText = GetMembersDetailGenerateChanceTop10000;
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandTimeout = 0; //no limit
cmd.Parameters.Clear();
cmd.Parameters.Add(new SqlParameter("QueryParam", QueryParam));
cmd.Parameters.Add(new SqlParameter("EventId", EventId));
cmd.Parameters.Add(new SqlParameter("PeriodId", PeriodId));
cmd.Connection = conn;
if (conn.State == ConnectionState.Open)
conn.Close();
conn.Open();
using (SqlDataReader reader = cmd.ExecuteReader())
{
while (reader.Read())
{
list.Add(new GenerateModel
{
ChanceNumber = reader["Chance_Number"].ToString(), //System.IndexOutOfRangeException Error
Receipt = reader["th name"].ToString(),
Date = reader["th createdon"].ToString(),
Initial = reader["new_Initial"].ToString(),
FirstName = reader["FirstName"].ToString(),
LastName = reader["LastName"].ToString(),
});
}
reader.Close();
}
}
return list;
}
I am confused as to how to implement his method because I want to get return of all select results in object model but I always get error
System.IndexOutOfRangeException : Chance_Number.
Honestly why do I use query select parameter is because I want to get value from checkedListBox1 that already I defined before by using this code get all checkedListBox1 value to determine select query.
string QueryParam = "cg.Chance_Number";//auto get chance_number as select mandatory
for (int i = 0; i < checkedListBox1.CheckedItems.Count; i++)
{
QueryParam += ", " + ((clsItemList)checkedListBox1.CheckedItems[i]).Value;
}
You have to use constructor with proper length for parameters as given below, to avoid the issue.Read more on SQLParameter
public SqlParameter (string parameterName, System.Data.SqlDbType dbType, int size);
cmd.Parameters.Add(new SqlParameter("QueryParam", SqlDbType.NVarChar,1000)).Value = QueryParam;
You need to make few more changes:
The way you have defined the procedure is wrong. You have to define the procedure as dynamic sql for the #queryparam to get concatenated to the SELECT query as given below:
DECLARE #selectStmt NVARCHAR(MAX) = ''
DECLARE #sqldefinition NVARCHAR(4000) = '#EventId nvarchar(255), #PeriodId nvarchar(255)'
SET #selectStmt += 'select distinct top 10000 ' + #QueryParam +
'from ign..Chance_Generated cg
inner join ign..Contact c on cg.ContactID = c.ContactId
left join ign..CustomerAddress ca on ca.parentid = cg.contactid
left join ign..new_cardlevelconfig cl on cl.new_cardlevelconfigid = c.new_cardlevel
left join ign..new_country co on co.new_countryid = c.new_country
left join ign..new_province po on po.new_provinceId = c.new_Province
left join ign..StringMap sm on sm.AttributeValue = c.new_IDType
left join ign..new_city cy on cy.new_cityId = c.new_CityCounty
left join ign..new_transactionheader th on cg.New_Name COLLATE DATABASE_DEFAULT = th.new_name COLLATE DATABASE_DEFAULT
where cg.EventId= '''+ #EventId +''' and (ca.AddressNumber = ''1'' or ca.AddressNumber is null) and (sm.AttributeName is null or sm.AttributeName = ''new_idtype'')
and cg.periodId = ''' + #PeriodId + ''';'
EXEC #sp_executesql #selectStmt, #sqldefinition, #EventId , #PeriodId
``
- Always refer the tables with proper schema in the query
ign.SchemaName.new_country
ign.SchemaName.new_province
I use bind variables to get data from the SQL tables.
The code:
string commandText = string.Format("SELECT {0} FROM {1} WHERE {2} ORDER BY {3}", fields, from, whereStr, orderBy);
DbCommand command = GetSqlCommandWrapper(commandText);
int index = 0;
foreach (var item in whereParams)
{
command.Parameters.Add(new OracleParameter(item, whereParamsBy[index++]));
}
DataTable db = new DataTable();
DataSet dataSet = null;
dataSet = CurrentDatabase.ExecuteDataSet(command);
The CommandText:
fields = "TableA.*";
from = "TableA INNER JOIN TableB ON TableA .id = TableB.id";
whereStr = "TableA .id > 10";
orderBy = "TableA .id, TableB .id";
Everything works fine until I have to get data from 2 tables like the query:
select * from a inner join b on a.id = b.id where....
Someone can tell me how to do it?
Thanks in advance
The overall approach is not very nice, but in terms of getting what you want, this should do it.
fields = "*";
from = "TableA AS a INNER JOIN TableB AS B ON a.id = b.id";
whereStr = "a.id > 10";
orderBy = "a.id, b.id";
Set your input parameters to that, or just paste it in before the code you gave us and it will produce the command SELECT * FROM TableA AS a INNER JOIN TableB AS B ON a.id = b.id WHERE a.id > 10 ORDER BY a.id, b.id
Please note that orderBy = "a.id; DROP TABLE TableA;"; is a scary prospect
I bind two columns into a dropdown using SQL like this
string query = "Select Id,Name+':'+Distribution_name+' 'as Name1 from BR_supervisor where( (id not in (select SupId from tbluser where active='true')) and active='true' ) ";
DropDownList3.DataTextField = "Name1";
DropDownList3.DataValueField = "Id";
DropDownList3.DataBind();
Now I want to transform my query into linq expression and bind the dropdown. How to do this?
var query = from s in db.BR_supervisor
join u in db.tbluser.Where(x => x.active)
on s.id equals u.SupId into g
where s.active && !g.Any()
select new {
s.Id,
Name1 = s.Name + ":" + s.Distribution_name
};
DropDownList3.DataTextField = "Name1";
DropDownList3.DataValueField = "Id";
DropDownList3.DataSource = query;
DropDownList3.DataBind();
This generates SQL like:
SELECT [t0].[Id], ([t0].[Name] + #p0) + [t0].[Distribution_name] AS [Name1]
FROM [BR_supervisor] AS [t0]
WHERE ([t0].[active] = 1) AND (NOT (EXISTS(
SELECT NULL AS [EMPTY]
FROM [tbluser] AS [t1]
WHERE ([t0].[id] = [t1].[SupId]) AND ([t1].[active] = 1)
)))
var query2 = (from a in this._projectDataContx.BR_Supervisors
where ((!(from x in this._projectDataContx.tblUsers
where (x.Active == true)
select x.SupId).Contains(a.Id))&&(a.Active==true))
select new { Name1 = a.Name + ":" + a.Distribution_Name, a.Id });
DropDownList3.DataSource = query2;
DropDownList3.DataTextField = "Name1";
DropDownList3.DataValueField = "Id";
DropDownList3.DataBind();
int id = 1;
string chain = "(";
SqlDataReader dr = SqlHelper.ExecuteReader(string.Format("SELECT a.Id as x, c.Id as y From Friends b INNER JOIN Users a ON b.SenderId = a.Id INNER JOIN Users c ON b.ReceiverId = c.Id WHERE (c.Id = {0} OR a.Id = {0}) AND State = '{1}'", id, "ok"));
if (dr.HasRows)
while (dr.Read())
if (id == int.Parse(dr["y"].ToString()))
chain += dr["x"].ToString() + ", ";
else
chain += dr["y"].ToString() + ", ";
if (chain.Length > 1)
chain = chain.Substring(0, chain.Length - 2) + ")";
else
chain = "(0)";
// Chain has for example => (2, 3, 4, 5) => which are the Ids for Users's Friends
string str = "SELECT TOP 20 a.*, b.UserName as Sender, c.UserName as Receiver, b.Avatar as SenderPic";
str += " FROM Events a INNER JOIN Users b ON a.SenderId = b.Id INNER JOIN Users c ON a.ReceiverId = c.Id ";
str += "WHERE SenderId IN ";
str += chain;
str += " OR ReceiverId IN";
str += chain;
str += " Order BY Id desc";
dr = SqlHelper.ExecuteReader(str);
chain considered as the user's friends .
does any one know how to execute this query with JOINS !? Thanks a lot ..
First, try to get rid of pushing parameter values with string.Format into SQL queries. That's a huge security issue.
To your query. I have to admit, I'm a bit lost in your string concatenation :-P, but if I'm right, you want to get the Events and some user information. As far as I can see, SenderId and ReciverId are already your ids. If so, you can completely remove the first SELECT and provide id (as parameter) directly into your second SQL statement like this (only the SQL):
Edit: Tom showed me the missing part (Status=Ok)
SELECT TOP(20)
a.*
,b.UserName as Sender
,c.UserName as Receiver
,b.Avatar as SenderPic
FROM Events a
INNER JOIN Users b ON a.SenderId = b.Id
INNER JOIN Users c ON a.ReceiverId = c.Id
WHERE
a.SenderId = #id
OR a.ReceiverId = #id;
Corrected version:
; WITH OkUsers AS (
SELECT
u.*
FROM Users u
JOIN Friends f ON u.Id = f.SenderId OR u.Id = f.RecipientId
WHERE
f.Status = 'Ok'
)
SELECT TOP(20)
a.*
,b.UserName as Sender
,c.UserName as Receiver
,b.Avatar as SenderPic
FROM Events a
INNER JOIN OkUsers b ON a.SenderId = b.Id
INNER JOIN OkUsers c ON a.ReceiverId = c.Id
WHERE
a.SenderId = #id
OR a.ReceiverId = #id;
SELECT distinct TOP(20) e.*, u1.UserName As Sender,
u2.UserName As Receiver, u1.Avatar AS SenderPic
FROM Friends f INNER JOIN Users u
ON(u.Id = f.SenderId OR u.Id = f.ReceiverId) AND State = 'ok'
INNER JOIN Events e
ON(f.SenderId = e.SenderId OR f.SenderId = e.ReceiverId
OR f.ReceiverId = e.SenderId OR f.ReceiverId = e.ReceiverId)
INNER JOIN Users u1
ON (e.SenderId = u1.Id)
INNER JOIN Users u2
ON (e.ReceiverId = u2.Id)
WHERE u.Id = #id;
I think that might help:
--step[1]
SELECT DISTINCT CASE
WHEN a.Id = 1 THEN c.ID
WHEN c.Id = 1 THEN a.Id
ELSE
0
END AS ID
INTO #OkUsers
From Friends b INNER JOIN Users a
ON b.SenderId = a.Id INNER JOIN Users c
ON b.ReceiverId = c.Id
WHERE (c.Id = #id OR a.Id = #id) AND State = 'Ok';
--step[2]
SELECT TOP 20 a.*, b.UserName as Sender, c.UserName as Receiver, b.Avatar as SenderPic
FROM Events a INNER JOIN Users b ON a.SenderId = b.Id INNER JOIN Users c ON a.ReceiverId = c.Id
INNER JOIN #OkUsers ON #OkUsers.ID = SenderId OR #OkUsers.ID = ReceiverId
EXCEPT
SELECT TOP 20 a.*, b.UserName as Sender, c.UserName as Receiver, b.Avatar as SenderPic
FROM Events a INNER JOIN Users b ON a.SenderId = b.Id INNER JOIN Users c ON a.ReceiverId = c.Id
--INNER JOIN #OkUsers ON #OkUsers.ID = SenderId OR #OkUsers.ID = ReceiverId
WHERE SenderId IN (SELECT ID FROM #OkUsers)
OR ReceiverId IN(SELECT ID FROM #OkUsers);
DROP TABLE #OkUsers;
Temp tables work good with very large volume of data.Otherwise you can use a memory table.
I am writing a c# unit test that validates string properties for an ORM class against the target database, always SQL 2008, and the class that the data maps to.
Checking that a specified foreign key is valid in the DB is easy:
static private bool ConstraintExsits(string table, string column, ConstraintType constraintType)
{
string constraintTypeWhereClause;
switch (constraintType)
{
case ConstraintType.PrimaryKey:
constraintTypeWhereClause = "PRIMARY KEY";
break;
case ConstraintType.ForeignKey:
constraintTypeWhereClause = "FOREIGN KEY";
break;
default:
throw new ArgumentOutOfRangeException("constraintType");
}
var cmd = new SqlCommand(
#"SELECT a.CONSTRAINT_NAME
FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS a
JOIN INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE b on a.CONSTRAINT_NAME = b.CONSTRAINT_NAME
WHERE a.TABLE_NAME = #table AND b.COLUMN_NAME = #column AND a.CONSTRAINT_TYPE = '" + constraintTypeWhereClause + "'",
Connection);
cmd.Parameters.AddWithValue("#table", table.Trim('[').Trim(']'));
cmd.Parameters.AddWithValue("#column", column.Trim('[').Trim(']'));
return !string.IsNullOrEmpty((string)cmd.ExecuteScalar());
}
Now take the following Foreign Key Relationships:
My question: How do I query the relationship from the 'Primary/Unique Key Base Table' and 'Primary/Unique Key Columns' side? I cannot see these referenced in the INFORMATION_SCHEMA views.
Thanks
J
This is the SQL that I was after!
SELECT
FK_Table = FK.TABLE_NAME,
FK_Column = CU.COLUMN_NAME,
PK_Table = PK.TABLE_NAME,
PK_Column = PT.COLUMN_NAME,
Constraint_Name = C.CONSTRAINT_NAME
FROM
INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS C
INNER JOIN
INFORMATION_SCHEMA.TABLE_CONSTRAINTS FK
ON C.CONSTRAINT_NAME = FK.CONSTRAINT_NAME
INNER JOIN
INFORMATION_SCHEMA.TABLE_CONSTRAINTS PK
ON C.UNIQUE_CONSTRAINT_NAME = PK.CONSTRAINT_NAME
INNER JOIN
INFORMATION_SCHEMA.KEY_COLUMN_USAGE CU
ON C.CONSTRAINT_NAME = CU.CONSTRAINT_NAME
INNER JOIN
(
SELECT
i1.TABLE_NAME, i2.COLUMN_NAME
FROM
INFORMATION_SCHEMA.TABLE_CONSTRAINTS i1
INNER JOIN
INFORMATION_SCHEMA.KEY_COLUMN_USAGE i2
ON i1.CONSTRAINT_NAME = i2.CONSTRAINT_NAME
WHERE i1.CONSTRAINT_TYPE = 'PRIMARY KEY'
) PT
ON PT.TABLE_NAME = PK.TABLE_NAME
Jaimie's answer fails to correctly return all the foreign keys if the referred table (the table that the foreign key is looking against) has a unique key because it uses the UNIQUE_CONSTRAINT_NAME column. I suggest:
SELECT
FK = fk.name,
FKTable = QUOTENAME(OBJECT_SCHEMA_NAME(fkcol.[object_id]))
+ '.' + QUOTENAME(OBJECT_NAME(fkcol.[object_id])),
FKCol = fkcol.name,
' references => ',
PKTable = QUOTENAME(OBJECT_SCHEMA_NAME(pkcol.[object_id]))
+ '.' + QUOTENAME(OBJECT_NAME(pkcol.[object_id])),
PKCol = pkcol.name
FROM sys.foreign_keys AS fk
INNER JOIN sys.foreign_key_columns AS fkc
ON fk.[object_id] = fkc.constraint_object_id
INNER JOIN sys.columns AS fkcol
ON fkc.parent_object_id = fkcol.[object_id]
AND fkc.parent_column_id = fkcol.column_id
INNER JOIN sys.columns AS pkcol
ON fkc.referenced_object_id = pkcol.[object_id]
AND fkc.referenced_column_id = pkcol.column_id
ORDER BY fkc.constraint_column_id;
Source:
The case against INFORMATION_SCHEMA views