Turning a table "on it's side" in asp.net - how? - c#

How do I turn this table:
+------------+-----------------+
| Category + Subcategory |
+------------+-----------------+
|Cat..........+ Persian.........|
|Cat..........+ Siamese........|
|Cat..........+ Tabby...........|
|Dog.........+ Poodle..........|
|Dog.........+ Boxer............|
+------------+----------------+
on it's side to get the following:
+------------+-----------------+
| Cat......... + Dog............. |
+------------+-----------------+
+ Persian..+ Poodle.........+
+ Siamese + Boxer...........+
+ Burmese + ...................+
+------------+-----------------+
The initial table is from the following MySQL query:
select c.CATEGORYNAME, sc.NAME from subcategorydefinition sc
join categorydefinition c on sc.CATEGORYID = c.CATEGORYID
where c.ISDELETED = 0
order by CATEGORYNAME, NAME ASC
And I want to display it in (probably) a Gridview.
Cheers!

Pivot is static in SQL. You need to know in advance the columns you want in output, so if the list of categories is not fixed, you can't use pivot directly.
If you were using Microsoft SQL Server (which I know you're not, but it's for the sake of example), you could use a dynamic query in a stored procedure, as described here:
http://www.simple-talk.com/community/blogs/andras/archive/2007/09/14/37265.aspx
Now, in MySql, there is no way to execute dynamic SQL on the sql side (no equivalent of EXECUTE or sp_executeqsl), so your best choice would be to generate a similar SQL query server-side (aspnet server-side).
Another simpler idea IMHO would be to forget about doing it in SQL, but to do the aggregation in your C# code.

You should use pivot

To do this in SQL, you'd need to dynamically generate your query based on the available set of values in the "Category" column. This is usually fairly painful and error prone, regardless of whether you do it in pure SQL (in a sproc) or in code (dynamic SQL).
I'd recommend reading your values from the database in the way that they are stored, then dynamically creating a DataTable or similar structure to use as the datasource for your UI.

I don't have a working version of MySql handy but this will work as long as there is always more cats than dogs because of the left join at the end of the script. I forgot that there isn't a full outer join in MySql but you could use this logic to try it out.
But the point of this is that if you have two tables with arbitrary keys you can join on the keys to get the results lined up like you want.
-- drop tables
DROP TABLE dbo.cat
DROP TABLE dbo.dog
--create dog table
create table dog (
dog_id int IDENTITY(1,1) NOT NULL
,dog varchar(50)
)
--add dogs only
insert into dog (dog)
select subcategory
FROM play.dbo.test
where category = 'Dog'
--create cat table
create table cat (
cat_id int IDENTITY(1,1) NOT NULL
,cat varchar(50)
)
--add cats only
insert into cat (cat)
select subcategory
FROM play.dbo.test
where category = 'cat'
-- disply everything
SELECT cat
, dog
from dog d
--full outer join cat c
left join dog d
on d.dog_id = c.cat_id

Related

Optimize a large in clause from list of integer

I would like to join on a large list of integers in SQL Server instead of a big IN clause.
My query :
SELECT
mmr.idContact,
mmR.idQuestion as IdQuestion,
MIN(mmR.idResponse) AS IdResponse
FROM MatchResponses mmR
--JOIN Contact c on c.idContact = mmR.idContact //to show the linked ids
JOIN Contact c on c.idSpecific in (1,2,3...10000)
WHERE myId= 300
GROUP By mmR.idContact, mmr.idQuestion
order by idContact, idQuestion
The IN clause is way too long, I can join mmR and COntact with an idContact.
The query takes 44s I would like to make it shorter using a JOIN
How can I declare the integers table "on the go" ?
My idea would be to handle the integer table using a temporary table in SQL. If you know the lower and upper limit of the integer table, it is easy to generate a temp_table in SQL and use it as a sub query with "In" Clause. It will not affect much on query performance.
Better to handle these from the DB rather than using an intermediate code to such as C# unless it is the requirement.
If you can attach sample schema and data, I can provide the code for you.
Thanks for all, I reseigned myself to simply not use the join or anything, no filter. The filtering wasn't more efficient, I after used LinQ (I only had 200 rows)
For the people looking for a solution :
I could have inserted all of the id in a temp table be careful you can't insert more than 1000 rows so use this trick:
DECLARE #tempTable TABLE (id INT)
INSERT INTO #EMPLOYEEDETAILS(id)
SELECT * FROM (VALUES
(1),(2),
.....
(10000)
) A(Col1)
And then the JOIN :
SELECT
mmr.idContact,
mmR.idQuestion as IdQuestion,
MIN(mmR.idResponse) AS IdResponse
FROM MatchResponses mmR
JOIN Contact c on c.idContact = mmR.idContact
JOIN #tempTable con on con.id = c.idSpecific
WHERE myId= 300
GROUP By mmR.idContact, mmr.idQuestion
order by idContact, idQuestion

C# Sql CTE Query - Select out extra information

I am trying to write a CTE Recursive Query to build a tree relationship of a flat table with a 'marketGroupID' (that element's ID) and a 'parentGroupID' (the element's parent ID). Where each 'marketGroup' can have any number of children 'marketGroups' and so on.
Here is my working query (tested in Sql Server Management):
With cte As
(SELECT [marketGroupID]
,[parentGroupID]
,[marketGroupName]
,[description]
,[iconID]
,[hasTypes]
, 0 As Level
FROM [Eve_Retribution_1.0.7].[dbo].[invMarketGroups]
WHERE [parentGroupID] IS NULL
UNION All
Select mg.marketGroupID
,mg.parentGroupID
,mg.marketGroupName
,mg.description
,mg.iconID
,mg.hasTypes
,c.Level + 1 As Level
FROM [Eve_Retribution_1.0.7].dbo.invMarketGroups mg
Inner Join cte c On mg.parentGroupID = c.marketGroupID
WHERE mg.marketGroupID <> mg.parentGroupID
)
SELECT marketGroupID
,parentGroupID
,marketGroupName
,description
,iconID
,hasTypes
, Level
FROM cte
This Query correctly lists the Elements in the correct order and the Level parameter is meant to be used to build the tree from the elements.
Translating this into C# is where I have a problem. I have integrated this database and all the corresponding tables have been built from my database into my code automatically. I try to call this query with C# as follows:
EveOnlineClassesDataContext context = new EveOnlineClassesDataContext();
IEnumerable<invMarketGroup> results = context.ExecuteQuery<invMarketGroup>
(#"**ABOVE QUERY**");
Where the 'invMarketGroup' class is the automatically created class built by the O/R Designer. My problem is that I lose access to the Level parameter for each 'marketGroup' as it was not part of the table itself and has no element in the provided class.
I want to retrieve from the query the actual 'invMarketGroup' class objects and the level corresponding to each so I can build a tree from this in memory representing this structure. How would I go about doing this?
Thanks
Might be easier to create a View vwInvMarketGroup inside your database using that query:
CREATE VIEW vwInvMarketGroup AS
With cte As
(SELECT [marketGroupID]
,[parentGroupID]
,[marketGroupName]
,[description]
,[iconID]
,[hasTypes]
, 0 As Level
FROM [Eve_Retribution_1.0.7].[dbo].[invMarketGroups]
WHERE [parentGroupID] IS NULL
UNION All
Select mg.marketGroupID
,mg.parentGroupID
,mg.marketGroupName
,mg.description
,mg.iconID
,mg.hasTypes
,c.Level + 1 As Level
FROM [Eve_Retribution_1.0.7].dbo.invMarketGroups mg
Inner Join cte c On mg.parentGroupID = c.marketGroupID
WHERE mg.marketGroupID <> mg.parentGroupID
)
SELECT marketGroupID
,parentGroupID
,marketGroupName
,description
,iconID
,hasTypes
, Level
FROM cte
GO
Then you can use this:
IEnumerable<invMarketGroup> results = context.ExecuteQuery<invMarketGroup>(#"SELECT * FROM vwInvMarketGroup");

Find Unused ID in Database using C# and SQL

I am trying to code a simple database management tool in C#. I am in the process of coding a function to insert a new row into the database, but I have run into a problem. I need to be able to detect which ID numbers are not already taken. I have done some research but haven't found any clear answers.
Example table:
ID Name
---------------
1 John
2 Linda
4 Mark
5 Jessica
How would I add a function that automatically detects that ID 3 is empty, and places a new entry there?
Edit: My real question is; When I want to insert a new row via C#, how do I handle a column which is auto-increment? An example would be fantastic :)
I don't like giving answers like this...but I am going to anyway on this occasion.
Don't
What if you store more data in another table which has a foreign key to the ID in this table? If you reuse numbers you are asking for trouble with referential integrity down the line.
I assume your field is an int? If so, an auto increment should give more than enough for most purposes. It makes your insert simpler, and maintains integrity.
Edit: You might have a very good reason to do it, but I wanted to make the point in case somebody comes along and sees this later on who thinks it is a good idea.
SQL:
SELECT ID From TABLE
OR
SELECT t.ID
FROM ( SELECT number + 1 AS ID
FROM master.dbo.spt_values
WHERE Type = 'p'
AND number <= ( SELECT MAX(ID) - 1
FROM #Table
)
) t
LEFT JOIN #Table ON t.ID = [#Table].ID
WHERE [#Table].ID IS NULL
C#
DataTable dt = new DataTable();
//Populate Dt with SQL
var tableInts = dt.Rows.Cast<DataRow>().Select(row => row.Field<int>("ID")).ToList<int>();
var allInts = Enumerable.Range(1, tableInts.Max()).ToList();
var minInt = allInts.Except(tableInts).Min();
SELECT #temp.Id
FROM #temp
LEFT JOIN table1 ON #temp.Id = table1.Id
WHERE table1.Id IS NULL
Try this?
But my suggestion is, just autoincrement the field.
How you do that is, you set the IDENTITY property of the column to true, and set it as Primary key too(not null).
To handle inserts, you might need triggers, which are like stored procedures, but they can act in place of insert or update or delete, or before/after insert/update/delete
Google triggers.
from How do I find a "gap" in running counter with SQL?
select
MIN(ID)
from (
select
0 ID
union all
select
[YourIdColumn]+1
from
[YourTable]
where
--Filter the rest of your key--
) foo
left join
[YourTable]
on [YourIdColumn]=ID
and --Filter the rest of your key--
where
[YourIdColumn] is null

Get All the information of table in SQL Server

I want to get all the information about a table.
Like tableName, columnName , InPrimaryKey , Is UniqueKey , Is Identity , Datatype, Maxlength, Is ForiegnKey
by using inbuilt api of SQL SERVER like information_schema.columns
You could start with:
EXEC sp_help 'dbo.tablename';
Then you could look at the columns directly:
SELECT
c.name,
[type] = t.name,
c.max_length,
c.[precision],
c.[scale],
c.is_nullable,
c.is_identity
FROM sys.columns AS c
INNER JOIN sys.types AS t
ON c.system_type_id = t.system_type_id
AND c.user_type_id = t.user_type_id
WHERE c.[object_id] = OBJECT_ID('dbo.tablename');
Indexes and participation in PK & unique constraints, foreign keys etc. are a little more complex, since multiple columns can participate in any of these entities. Here are indexes and PK/UQ constraints:
SELECT
[index] = i.name,
i.type_desc,
i.is_unique,
i.is_primary_key,
i.is_unique_constraint,
c.name,
ic.is_included_column
FROM sys.indexes AS i
INNER JOIN sys.index_columns AS ic
ON i.[object_id] = ic.[object_id]
INNER JOIN sys.columns AS c
ON ic.[object_id] = c.[object_id]
AND ic.index_id = i.index_id
AND ic.column_id = c.column_id
WHERE i.[object_id] = OBJECT_ID('dbo.tablename');
And then you could move on to foreign keys by looking at sys.foreign_keys and sys.foreign_key_columns. This is even more convoluted than above - are you looking for all the foreign keys of the current table that point at other tables, all the foreign keys in other tables that point at this one, or both?
Use SQL Server Management Objects (SMO). This is a convenient and fully managed API to get and manipulate the schema of a SQL Server database.
You can do a
select * from table where 0 = 1
into a data-table. The columns will be copied and are ready to be inspected.
If you want a working project, my stored procedure generator / class object creator reads the database schema for all tables and views in a database.
The code is available at http://radstudio.codeplex.com
The file called DataClassBuilder.Net.dll contains a method called LoadDatabaseSchema() and LoadDataFieldsSchema() should give you all the information you need about the data.

Adding a Column Programmatically to a SQL Server database

I've taken over an ASP.NET application that needs to be re-written. The core functionality of this application that I need to replicate modifies a SQL Server database that is accessed via ODBC from third party software.
The third-party application creates files that represent printer labels, generated by a user. These label files directly reference an ODBC source's fields. Each row of the table represents a product that populates the label's fields. (So, within these files are direct references to the column names of the table.)
The ASP.NET application allows the user to create/update the data for these fields that are referenced by the labels, by adding or editing a particular row representing a product.
It also allows the occasional addition of new fields... where it actually creates a new column in the core table that is referenced by the labels.
My concern: I've never programmatically altered an existing table's columns before. The existing application seems to handle this functionality fine, but before I blindly do the same thing in my new application, I'd like to know what sort of pitfalls exist in doing this, if any... and if there are any obvious alternatives.
It can become problem when too many columns are added to tables, and you have to be careful if performance is a consideration (covering indexes are not applicable, so expensive bookmark lookups might be performed).
The other alternative is a Key-Value Pair structure: Key Value Pairs in Database design, but that too has it's pitfalls and you are better off creating new columns, as you are suggesting. (KVPs are good for settings)
One option I think is to use a KVP table for storing dynamic "columns" (as first mentioned by Mitch), join the products table with the KVP table based on the product id then pivot the results in order to have all the dynamic columns in the resultset.
EDIT: something along these lines:
Prepare:
create table Product(ProductID nvarchar(50))
insert Product values('Product1')
insert Product values('Product2')
insert Product values('Product3')
create table ProductKVP(ProductID nvarchar(50), [Key] nvarchar(50), [Value] nvarchar(255))
insert ProductKVP values('Product1', 'Key2', 'Value12')
insert ProductKVP values('Product2', 'Key1', 'Value21')
insert ProductKVP values('Product2', 'Key2', 'Value22')
insert ProductKVP values('Product2', 'Key3', 'Value23')
insert ProductKVP values('Product3', 'Key4', 'Value34')
Retrieve:
declare #forClause nvarchar(max),
#sql nvarchar(max)
select #forClause = isnull(#forClause + ',', '') + '[' + [Key] + ']' from (
select distinct [Key] from ProductKVP /* WHERE CLAUSE */
) t
set #forClause = 'for [Key] in (' + #forClause + ')'
set #sql = '
select * from (
select
ProductID, [Key], [Value]
from (
select k.* from
Product p
inner join ProductKVP k on (p.ProductID = k.ProductID)
/* WHERE CLAUSE */
) sq
) t pivot (
max([Value])' +
#forClause + '
) pvt'
exec(#sql)
Results:
ProductID Key1 Key2 Key3 Key4
----------- --------- --------- --------- -------
Product1 NULL Value12 NULL NULL
Product2 Value21 Value22 Value23 NULL
Product3 NULL NULL NULL Value34
It very much depends on the queries you want to run against those tables. The main disadvantage of KVP is that more complex queries can become very inefficient.
A "hybrid" approach of both might be interesting.
Store the values you want to query in dedicated columns and leave the rest in an XML blob (MS SQL has nice features to even query inside the XML) or alternatively in a KVP bag. Personally I really don't like KVPs in DBs because you cannot build application logic specific indixes anymore.
Just another approach would be not to model the specific columns at all. You create generic "custom attribute" tables like: Attribute1, Attribute2, Attribute3, Attribute4 (for the required data type etc...) You then add meta data to your database that describes what AttrX means for a specific type of printer label.
Again, it really depends on how you want to use that data in the end.
One risk is the table getting too wide. I used to maintain a horrible app that added 3 columns "automagically" when new values were added to some XML (for some reason it thought everything would be a string a date or a number- hence the creation of 3 columns).
There are other techniques like serializing a BLOB or designing the tables differently that may help.

Categories