Saving an array of strings to an SQL column - c#

I want to create a "sessions" table in an SQL database for a school project. Each session should have:
Session ID
Lecturer name
Time and date
Module name
Course name
List of student IDs
List of student statuses(Present, absent, late)
How can I represent such a thing ???
Is it better to create ONE table to represent all sessions, where each session would be one row, and have an array of strings in each column that represents the names, IDs, and status of students??
OR
Create a new table for each new session ??
What is better, and please explain how to do it briefly.
Bear in mind, that I would need to insert/delete/update/view each table from a C# windows application, and the maximum expected number of sessions is just 100.
Also, I am using SQL Server 2012 with a C# windows application developed with Visual Studio 2012
Thanks

I think you should have 3 tables :
Students
------------------------------------
| StudentID | FirstName | LastName |
|-----------|-----------|----------|
| 4456 | John | Doe |
| 6678 | Billy | Bob |
------------------------------------
Here StudentID is Primary Key
Sessions
---------------------------------------------------------------------
| SessionID | Lecturer | DateTime | Module | Course |
|-----------|----------|----------|------------------|--------------|
| 1 | Mr.Joe | 524523461| Natural Sciences | Oceanography |
---------------------------------------------------------------------
Here dateTime would be a Unix Timestamp and SessionId is Primary Key
SessionAttendance
-------------------------------------
| SessionID | StudentID | Status |
|-----------|-----------|-----------|
| 1 | 4456 | 'Late' |
| 1 | 6678 | 'Present' |
-------------------------------------
Here SessionID and StudentID are both Primary Keys
Reason
Here you don't need to parse all the lists of attendance and statuses. The queries may get a little bigger, but it will save you alot of parsing code.
Example Query :
SELECT SessionID FROM SessionAttendance WHERE StudentID = (SELECT StudentID FROM Students WHERE FirstName = 'John' AND LastName = 'Doe') AND Status = 'Late';
It will get all the sessions in which John Doe was late. Simple, right?
Other Comments
You cannot store arrays of information in an database column. It
must be a list that is delimited somehow
In your application, I reccomend you always keep the StudentID with
its FirstName and LastName because it will make queries easier, and
will keep the names localized (so that you can change it in one
place and will change everywhere else)

Related

Multiple incremental series with different prefix in SQL Server?

Here is the scenario:
Config Table:
+--------+-----------+-------+
| Prefix | Separator | Seed |
+--------+-----------+-------+
| A | # | 10000 |
+--------+-----------+-------+
Transaction Table:
+----+----------+------+
| Id | SerialNo | Col3 |
+----+----------+------+
| 1 | A#10000 | |
| 2 | A#10001 | |
+----+----------+------+
The Transaction table has a SerialNo column that has a sequential number generated based on configuration table. Configuration table determines the prefix separator and the seed value of the serial number.
In the above example the serial number would start at A#10000 and increment by 1.
But if after few months someone updates the configuration table to have
+--------+-----------+-------+
| Prefix | Separator | Seed |
+--------+-----------+-------+
| B | # | 10000 |
+--------+-----------+-------+
Then the Transaction table is supposed to look something like this:
+----+----------+------+
| Id | SerialNo | Col3 |
+----+----------+------+
| 1 | A#13000 | |
| 2 | B#10001 | |
+----+----------+------+
However there could be no duplicate serial numbers at any given point in time in Transaction table.
If someone sets Prefix back to A and seed to 10000 then the next serial number should not be A#10000 because it already exists. It should be A#13001
One could simply write a select query with MAX() and CONCAT() by then it could cause issues with concurrency. Don't want to have duplicate serial numbers. Also, would want to have this as performance friendly as possible.
Another solution that I could come up with is that I create a windows service that will keep on running and watching the table. The records get inserted with null as serial number and the windows service will update the serial number. This way there will be no concurrency issues but then I am not sure how reliable this is. There will be delays.
There will only be one entry in configuration table at any given point in time.
You can solve the seed value problem quite easily in SQL Server. When someone updates the seed value back to 10000 you will need to do this via a stored procedure. The stored procedure then determines what the actual next available value should be because clearly 10000 could be the wrong value. The stored procedure then executes DBCC CHECKIDENT with the correct "new_reseed_value". Then when new records are inserted the server will handle the values again correctly.
Please look at this link for usage on the DBCC CHECKIDENT command. SQL Server DBCC CHECKIDENT

For a MVC application, update values of multiple columns every 3 months in database and send e-mail

For a MVC application I am developing, I need to update the values of certain columns of a table in database every quarter i.e. on 1st day of Jan, Apr, July and Oct every year.
For example, if the table currently looks something like:
+-------+------------------+---------------+----------------+----------------------+---------------+------------+------------+
| EmpId | Experience_Prior | Qualification | Specialization | Status | LastSubmitted | NextDue | ApprovedOn |
+-------+------------------+---------------+----------------+----------------------+---------------+------------+------------+
| EmpId | 0.00 | B.Tech | CSE | Assessment Submitted | 2016-11-20 | 2017-01-01 | 2016-11-20 |
+-------+------------------+---------------+----------------+----------------------+---------------+------------+------------+
Then on the 1st day of next quarter, the columns Status, LastSubmitted, NextDue and ApprovedOn have to be updated as:
+-------+------------------+---------------+----------------+--------------------+---------------+------------+------------+
| EmpId | Experience_Prior | Qualification | Specialization | Status | LastSubmitted | NextDue | ApprovedOn |
+-------+------------------+---------------+----------------+--------------------+---------------+------------+------------+
| EmpId | 0.00 | B.Tech | CSE | Assessment Overdue | NULL | 2017-01-04 | NULL |
+-------+------------------+---------------+----------------+--------------------+---------------+------------+------------+
In case it's unclear, NextDue should be updated to the 1st day of next quarter.
This has to be followed by an email to all users using the application.
I know how to update the columns and send emails from the application. I just need to know how to execute all these every quarter.
The application is an intranet MVC4 application and the database is SQL Server 2008 R2 Express.
You have two options, Use Background job to update it ex(HangFire), But you will have another challenge that you can't use system.net and smtp to send emails as there is no HttpRequest, you will have to use service for sending ex (mailgun) or may be there is a workaround for that !!.
second option, Create a static variables contains last modified dates (or table in db) and check it with Current date everytime you will update, If Ok do your update, send emails, update last modified date again.
Hope that help
Use cronjob or Quartz scheduler that will Schedule and trigger on 1st date of every Quarter to run your Java Program/Application and update the Database columns.

how will i create multiple type id in one column database design

I am designing SQL Server database and i have to create multiple FK in one column
so I have these tables and create a menu in one table
Table 1 Table 2 Table 3
| Pages | Jobs | News
|------------ |--------- |-----------
| Pageid | Jobid | NewsId
| PageName | JobName | NewsTitle
| MenuName | MenuName | MenuName
My aim is to reference these table in one column
I have a table from this scenario
| MenuGroup
|------------
| menuGroupId
| MenuName
| RecordeId
So how will i achieve the normalize database design?
Sol 1 (Fixed no of Columns):
This is the most standard and normalized solution. You can create a new table with nullable columns as suggested by #Tim
| JoiningTable
|------------
| Id
| PageId
| JobId
| NewsId
Sol2:(Dynamic no of Columns):
Although I do not consider it a good approach , since referential integrity is lost here, but in case of dynamic number of columns I don't have anyother solution except this one.
Type:
|------------
| TypeId
| Name
JoiningTable
|------------
| Id
| JoiningId
| TypeId (news,job,pages etc etc)
You can compress these two tables into one by replacing a TypeId with type field in JoiningTable.
NoSQl may also be a solution but I have no experience of working on NOSQL so I cannot recommend you anything about that.
I will suggest you create another table that has the 3 tables' ids as foreign keys then use the primary key of this new table in MenuGroup table and you can use LEFT JOIN to get individual tables through the new table.
Having multiple FK's in a single table isn't bad, try using the MenuName column as FK so you won't have to create an extra field in your database.

Generating a unique primary key

I have a SQL Server database that will contain many tables that all connect, each with a primary key. I have a Dictionary that keeps track of the the primary keys fields are for each table. My task is to extract data every day from attribute-centric XML files and insert them into a master database. Each XML file has the same schema. I'm doing this by using an XMLReader and importing the data into a DataSet.
I can't use an AutoNumber for the keys. Let's say yesterday's XML file produced a DataTable similar to the following, and it was imported into a database
-------------------------------------
| Key | Column1 | Column2 | Column3 |
|-----------------------------------|
| 0 | dsfsfsd | sdfsrer | sdfsfsf |
|-----------------------------------|
| 1 | dertert | qweqweq | xczxsdf |
|-----------------------------------|
| 2 | prwersd | xzcsdfw | qwefkgs |
-------------------------------------
If today's XML file produces the following DataTable
-------------------------------------
| Key | Column1 | Column2 | Column3 |
|-----------------------------------|
| 0 | sesdfsd | hjghjgh | edrgffb |
|-----------------------------------|
| 1 | wrwerwr | zxcxfsd | pijghjh |
|-----------------------------------|
| 2 | vcbcvbv | vbnvnbn | bnvfgnf |
-------------------------------------
Then when I go to import the new data into the database using SqlBulkCopy, then there will be duplicate keys. My solution to this is to use DateTime.Now.Ticks to generate unique keys. Theoretically, this should always create a unique key.
However, for some reason DateTime.Now.Ticks is not unique. For example, 5 records in a row might all have the key 635387859864435908, and the next 7 records might have the key 635387859864592164, even though I am generating that value at different times. I want to say that the cause of the problem is that my script is calling DateTime.Now.Ticks several times before it updates the time.
Can anyone else think of a better way to generate keys?
It's possible that the value of DateTime.Now is cached for a small amount of time for performance reasons. We do something similar to this and there are 2 possible options that we use:
Keep a list of numbers that you've used on the server you're on and increment if you can determine the number has already been used
Convert the field to a string and append a GUID or some other random identifier on the end of it. A GUID can be created with System.Guid.NewGuid().ToString();
Obviously neither of these plans are going to make the risk of collision zero, but they can help in reducing it.
If you have huge amount of data and you need to have a unique key for each row just use GUID
You could do something like the following to get a unique id (SQL Fiddle):
SELECT
CONCAT(YEAR(GETDATE()), DATEDIFF(DAY, STR(YEAR(GETDATE()), 4) + '0101',
GETDATE() ) + 1, ROW_NUMBER() OVER(ORDER BY id DESC)) UniqueID
FROM supportContacts s
This would work if you only run the query once per day. If you ran it more than once per day you would need to grab the seconds or something else (SQL Fiddle):
SELECT CONCAT(CurrYear, CurrJulian, CurrSeconds, Row) AS UniqueID
FROM
(
SELECT
YEAR(GETDATE()) AS CurrYear,
DATEDIFF(DAY, STR(YEAR(GETDATE()), 4) + '0101', GETDATE() ) + 1 AS CurrJulian,
ROW_NUMBER() OVER(ORDER BY id DESC) AS Row,
datediff(second, left(convert(varchar(20), getdate(), 126), 10), getdate()) AS CurrSeconds
from supportContacts s
) AS m

Permission management by tab removal using SQL

I need an idea. I have an app, a winform having multiple tabs in it. There are a bunch of people using it, but none of them needs to use all the tabs, just a couple of them. I've reached a point where it's hard to handle from the source code, so I need a solution to easily manage the permissions. The best would be to use an SQL table for this as I also have to provide for another guy the possibility to modify the rights. I think it would be fine to simply remove the tabs by creating an sql table like this, and at the program startup simply query something like this:
select tabid from table where loggedinuser = 0
and then just loop through the result and remove all of them
foreach(tabid in tabids)
{
tabControl1.TabPages.RemoveByKey(tabid);
}
table:
+----------+----------+-------+-------+-------+
| tabid | name | user1 | user2 | user3 |
+----------+----------+-------+-------+-------+
| tabPage1 | project1 | 0 | 1 | 0 |
+----------+----------+-------+-------+-------+
| tabPage2 | project2 | 1 | 0 | 1 |
+----------+----------+-------+-------+-------+
| tabPage3 | project3 | 1 | 0 | 0 |
+----------+----------+-------+-------+-------+
However I somehow feel that this is not an elegant solution, especially because you have create a new column each time a new guy has to be added. Do you have any idea how to solve it?
I think this is an issue of the database's design, and a basic one; perhaps you need to improve your understanding of SQL databases, particularly relationships and primary/foreign keys. You shouldn't add new columns but new rows.
You need a table for the users, one for the tabs and one to connect the two. Such as this:
User:
+---------+------+
| user_id | name |
+---------+------+
| 1 | John |
+---------+------+
| 2 | Jane |
+---------+------+
Tab:
+--------+----------+
| tab_id | title |
+--------+----------+
| 1 | Articles |
+--------+----------+
| 2 | Products |
+--------+----------+
UserTab:
+---------+--------+---------+
| user_id | tab_id | enabled |
+---------+--------+---------+
| 1 | 1 | 1 |
+---------+--------+---------+
| 1 | 2 | 0 |
+---------+--------+---------+
| 2 | 1 | 0 |
+---------+--------+---------+
| 2 | 2 | 1 |
+---------+--------+---------+
In this example, John can only access Articles and Jane can only access Products.
You should get the ID of the current user and get the entries from UserTab, then remove the tabs that correspond to the IDs for which enabled=0.
You also should make a "default" choice for when the right combination of user and tab doesn't exist in the UserTab table: either display the tab by default or hide it by default.
If you do it through SQL, a simple data model could be :
USER TABLE would have fields user_id,username,... all USER related fields you wish
ROLE TABLE would have fields role_id,role_name
USERROLE TABLE would have fields f_user_id,f_role_id(both foreign keys)
Each record (line) in this table links a user to a role, so a user can have many roles, and a role can be attribuated to many users. That's called a many-to-many relationship
ROLERIGHT TABLE would have fields f_role_id,tabid
Each record (line) in this table links a role to a tab that this role has access to. That means if a role should access all tabs and you've got 10 tabs, you'll have 10 lines with the same role_id and a different tabid from 1 to 10. It is also a many-to-many relationship.
This is quite an usual database pattern for access right management I guess. Now what you have to do is define the several roles. And assign it to the different users. If a new user comes in and he should have the same rights as another user, you just have to assign him the same role(s) as the other user. Depending on complexity and the number of possible tabs/users combinations, you will or not have many roles with few rights, or a few roles with access to several tabs. The latter would probably be the case for a limited number of users, but the good thing is that you could easily scale up without changing the model, only the data.

Categories

Resources