LINQ to SQL sum null value - c#

I have the following query, I'd like to sum the NULL value also. Some TimeSheet don't records in TimeRecord and some tr.TimeIn and tr.TimeOut are NULL.
The query select only TimeSheet that has reords in TimeRecord. How I can have it select everything, and sum up the NULL value as well. So, the SUM of NULL will be just zero.
Table relationship:
Student 1:N TimeSheet (FK StudentId)
TimeSheet 1:N TimeRecord (FK TimeSheetId)
TimeIn and TimeOut are DateTime type and nullable.
Query 1: Monthy Report:
Dim query = From ts In db.TimeSheets _
Join tr In db.TimeRecords On tr.TimeSheetId Equals ts.TimeSheetId _
Where ts.IsArchive = False And ts.IsCompleted = False And tr.TimeOut IsNot Nothing _
Group By key = New With {ts.Student, .MonthYear = (tr.TimeOut.Value.Month & "/" & tr.TimeOut.Value.Year)} Into TotalHour = Sum(DateDiffSecond(tr.TimeIn, tr.TimeOut)) _
Select key.Student.StudentId, key.Student.AssignedId, key.MonthYear, TotalHour
Query 2: Total TimeRecord for Student with Active TimeSheet:
Dim query = From ts In db.TimeSheets _
Join tr In db.TimeRecords On tr.TimeSheetId Equals ts.TimeSheetId _
Where ts.IsArchive = False And ts.IsCompleted = False _
Group By ts.StudentId, tr.TimeSheetId Into TotalTime = Sum(DateDiffSecond(tr.TimeIn, tr.TimeOut)) _
Select StudentId, TimeSheetId, TotalTime
Here's the result of the query 2:
734 -- 159 : 9 hrs 35 mm 28 sec
2655 -- 160 : 93 hrs 33 mm 50 sec
1566 -- 161 : 37 hrs 23 mm 53 sec
3114 -- 162 : 25 hrs 0 mm 21 sec
Wanted result of Query 2:
733 -- 158 : 0 hr 0mm 0 sec
734 -- 159 : 9 hrs 35 mm 28 sec
736 -- 169 : 0 hrs 0mm 0sec
2655 -- 160 : 93 hrs 33 mm 50 sec
1566 -- 161 : 37 hrs 23 mm 53 sec
3114 -- 162 : 25 hrs 0 mm 21 sec
Same for Query 1 but it makes monthly report.

I apologise because I translated your query to C# before tweaking it, and I don’t really know the VB syntax well enough to translate it back, but I hope that you will be able to. I tried the following query and it does what you asked for:
var query = from st in Students
select new
{
st.StudentId,
st.AssignedId,
TotalHour = (
from ts in TimeSheets
where ts.StudentId == st.StudentId
join tr in TimeRecords on ts.TimeSheetId equals tr.TimeSheetId
where !ts.IsArchive && !ts.IsCompleted && tr.TimeOut != null
select (tr.TimeOut.Value - tr.TimeIn).TotalHours
).Sum()
};
I had to remove the MonthYear thing because I didn’t really understand how that fit in with your grouping, but since it’s not in the output, I suspected that maybe you don’t need it.
I had to make a few assumptions:
I am assuming that TimeOut is a DateTime? (nullable) while TimeIn is DateTime (non-nullable). I think that makes sense.
I am assuming that TimeSheets have a StudentId that links them to students.

Related

SQL to LINQ - Getting Wrong Results

If a user selects 07-07-2016, I want to count how many times billdays > 30 for that billdate month, for the past 12 months.
Query is this:
select COUNT(*) as 'BillsOver30' from pssuite_web.pujhaccd
where billdays>30 and DATEDIFF(month,'07-07-2016', GETDATE()) <= 13
Group By Month(billdate)
Result is this:
1784 (July)
1509 (June)
2986 (May)
2196 (etc)
5853
3994
1753
1954
869
1932
629
1673
LINQ query is:
DateStart = '07-07-2016' (from a textbox on view)
DateTime earliestDate = objdate1.DateStart.Value.AddMonths(-13);
var custQuery9 = (from m in DataContext.pujhaccds
where m.billdays > 30 &&
m.billdate >= earliestDate &&
m.billdate <= objdate1.DateStart
group m by m.billdate.Value.Month into p
select new Date1()
{
theMonth = p.Key,
theCount = p.Count()
});
Results are:
Month Count
1 1029
2 1018
3 1972
4 1519
5 2657
6 2019
7 1206
8 1023
9 761
10 1620
11 354
12 931
You can see that the LINQ query is way off.
Doesn't matter what date I put in, the result always stays the same. Rather than 12 months from starting date.
I must be writing it wrong, thanks.

convert rows to columns in Access

I have read many question on Stack Overflow related to my problem, but I don't think they quite address my problem. Basically I download a XML dataset with lots of data, and inserted that data into my MS Access database. What I want to do is convert the data so that some specific rows become columns.
Now I can probably do this manually in code before inserting the data to database, but that would require lots of time and change in code, so I'm wondering if its possible to do this with MS Access.
Here's how my table basically looks, and how I want to convert it.
The index is not so relevant in my case
[Table1] => [Table1_converted]
[Index] [Name] [Data] [NameID] [NameID] [AA] [BB] [CC] [DD]
1 AA 14 1 1 14 date1 64 61
2 BB(date) 42 1 2 15+19 date2 67+21 63+12
3 CC 64 1 3 9 10
4 DD 61 1 4 date4 1 87
5 AA 15 2
6 BB(date) 35 2
7 CC 67 2
8 DD 63 2
9 AA 9 3
10 CC 10 3
11 AA 19 2
12 BB(date) 20 2
13 CC 21 2
14 DD 12 2
15 BB(date) 83 4
16 CC 1 4
17 DD 87 4
Forgot to mention that, the Values under the column [Name] are not really AA BB CC.
They are more complex then that. AA is actually like "01 - NameAA", without the quotation mark.
Forgot to mention one important element in my question, if the [Name] ex. AA with same [NameID] exists in table, then the [Data] should SUM up those two values. I have edited the tables, on the converted table i have written ex. 15+19 or 35+20 which only illustrates which values are summed up.
One more edit, hopefully the last. One of the [Name] BB has a Datetime type in [Data].
The NameID can be whichever, does not matter. So i need a query which does an exception on [Name] BB when its summing up, so that it does not sum it up like it does to every other [Name]s [Data]. Places where date is written multiple times for same [Name] and [NameID], it is always the same.
To accomplish this in Access, all you need to do is
TRANSFORM Sum([Data]) AS SumOfData
SELECT [NameID]
FROM [Table1]
GROUP BY [NameID]
PIVOT [Name]
edit re: revised question
To handle some [Name]s differently we would need to assemble the results (Sum()s, etc.) first, and then crosstab the results
For test data in [Table1]:
Index Name Data NameID
----- ---- ---------- ------
1 AA 14 1
2 BB 2013-12-01 1
3 CC 64 1
4 DD 61 1
5 AA 15 2
6 BB 2013-12-02 2
7 CC 67 2
8 DD 63 2
9 AA 9 3
10 CC 10 3
11 AA 19 2
12 BB 2013-12-02 2
13 CC 21 2
14 DD 12 2
15 BB 2013-12-04 4
16 CC 1 4
17 DD 87 4
the query
TRANSFORM First(columnData) AS whatever
SELECT [NameID]
FROM
(
SELECT [NameID], [Name], Sum([Data]) AS columnData
FROM [Table1]
WHERE [Name] <> 'BB'
GROUP BY [NameID], [Name]
UNION ALL
SELECT DISTINCT [NameID], [Name], [Data]
FROM [Table1]
WHERE [Name] = 'BB'
)
GROUP BY [NameID]
PIVOT [Name]
produces
NameID AA BB CC DD
------ -- ---------- -- --
1 14 2013-12-01 64 61
2 34 2013-12-02 88 75
3 9 10
4 2013-12-04 1 87
Try this...in sql query may be it is your answer
SELECT NameID , [AA] as AA,[BB] as BB,[CC] as CC,[DD] as DD
FROM
(
SELECT Name,Data,NameID FROM Table1
)PivotData
PIVOT
(
max(Data) for Name in ([AA],[BB],[CC],[DD])
) AS Pivoting
I think you need to this
1) Take all your Table1 as it is in SQL Server
2) Then run following query
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT distinct ',' + QUOTENAME(Name)
from [Table1]
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT countryid,' + #cols + '
from
(
select NameID, Name
from Table1 cc
) T
pivot
(
max (Name)
for languagename in (' + #cols + ')
) p '
execute sp_executesql #query;
DECLARE #Table1 TABLE ([Index] INT,[Name] CHAR(2),[Data] INT,[NameID] INT)
INSERT INTO #Table1
VALUES
(1,'AA',14,1),
(2,'BB',42,1),
(3,'CC',64,1),
(4,'DD',61,1),
(5,'AA',15,2),
(6,'BB',35,2),
(7,'CC',67,2),
(8,'DD',63,2),
(9,'AA',9,3),
(10,'CC',10,3),
(11,'BB',83,4),
(12,'CC',1,4),
(13,'DD',87,4)
SELECT [NameID] , ISNULL([AA], '') AS [AA], ISNULL([BB], '') AS [BB]
, ISNULL([CC], '') AS [CC], ISNULL([DD], '') AS [DD]
FROM
(
SELECT NAME, DATA, NAMEID
FROM #Table1
)q
PIVOT
(
SUM(DATA)
FOR NAME
IN ([AA], [BB], [CC], [DD])
)P
Result Set
NameID AA BB CC DD
1 14 42 64 61
2 15 35 67 63
3 9 10
4 83 1 87

Update all records using a function sql

I am looking to update a calculated sum in sql
Basically I have a table:
ImportID SeiralNumber Day Hour value Difference Complete
1 123 1 1 6 NULL 0
2 123 1 2 8 NULL 0
3 123 1 5 21 NULL 0
4 123 1 6 28 NULL 0
5 222 2 2 12 NULL 0
6 222 2 5 18 NULL 0
7 222 2 4 16 NULL 0
8 222 1 12 8 NULL 0
For each serial number there will be a day 1-365 and hour through 1-12, all I want to do is calculate the difference filed from the record before
So take ImportID 6, I need to get the record which is on the same day and the hour before (importID 7) then I need to update the Difference using the value field which is 18 -17 = 1.
N.B. There may be gaps in the sequence and if there is no previous record then the difference should stay as NULL. Once they have been calculated they need to be inserted into a new table only when the difference is now not null and it doesn't exist in the table already, on a successful insert they get marked as complete. Also a record before can be a previous day (day 1 hour 12) is the record before (day 2, hour 1)
Currently I am using a loop to select the null values, get the previous record, update the record, if its OK insert into other table, update the Completed field.
My issue is that this is working on a million records and it is taking a long while to Select the applicable records (completed = 0) into a temp table and loop through each.
Is there any quicker way to mass process these as an update statement? Or separate statements?
The result should be
ImportID SeiralNumber Day Hour value Difference Complete
1 123 1 1 6 NULL 0
2 123 1 2 8 2 1
3 123 1 5 21 NULL 0
4 123 1 6 28 7 1
5 222 2 1 12 4 1
6 222 2 5 18 2 1
7 222 2 4 16 NULL 0
8 222 1 12 8 NULL 0
Thanks in advance
I think this is basically it isn't it?
DECLARE #TABLE TABLE
(
ImportId INT,
SerialNumber INT,
Day INT,
Hour INT,
Value INT,
Difference INT,
Complete INT
)
INSERT INTO #TABLE VALUES
(1,123,1,1,6,NULL,0),
(2,123,1,2,8,NULL,0),
(3,123,1,5,21,NULL,0),
(4,123,1,6,28,NULL,0),
(5,222,2,1,12,NULL,0),
(6,222,2,5,18,NULL,0),
(7,222,2,4,16,NULL,0),
(8,222,1,12,8,NULL,0)
SELECT * FROM #Table
UPDATE T
SET T.Difference = T.Value - TT.Value,
Complete = 1
FROM
(
SELECT *
,ROW_NUMBER() OVER (PARTITION BY SerialNumber ORDER BY Day ASC, Hour ASC) AS RowCounter
FROM #TABLE
WHERE Complete = 0 --Ignore completed ones
)AS T
INNER JOIN
(
SELECT *
,ROW_NUMBER() OVER (PARTITION BY SerialNumber ORDER BY Day ASC, Hour ASC) AS RowCounter
FROM #TABLE
)AS TT
ON T.SerialNumber = TT.SerialNumber
WHERE
(
T.RowCounter = TT.RowCounter + 1
AND
T.Day = TT.Day
AND
T.Hour = TT.Hour + 1
)
OR
(
T.Day = TT.Day + 1
AND
T.Hour = 1
AND
TT.Hour = 12
)
SELECT * FROM #TABLE

Selecting the (number of) columns dyanamically using linq to sql

I have a table like this
Student Exam p1 p2 p3 p4 p5 p6 p7 p8 p9 p10 p11 p12
-----------------------------------------------------------------------------------
100 unit1 89 56 59 28 48 38 0 0 0 0 0 0
100 unit2 89 56 59 0 0 0 0 0 0 0 0 0
100 unit3 89 56 59 28 48 38 0 0 0 0 0 0
100 unit4 89 56 59 28 48 0 0 0 0 0 0 0
another table
Exam Num_subjects
----------------------
unit1 6
unit2 3
unit3 6
unit4 5
now i need to select the only first 8 columns in the marks table for unit1 as the number of subject for the unit1 is 6 .. how to do this dynamically ...
exam is foreign key to the marks table in linq to sql any ideas ...
If you have a column based design, since L2S doesn't let you manually materialize (i.e. new MyTable { Foo = row.Foo /* omit some } you are a bit scuppered.
If you just want the data, you could use something like "dapper" which won't have this issue, but you'll need to write the TSQL yourself, i.e.
var rows = conn.Query<MyTable>("select p1, p2, p3, p4, p5 from MyTable where Exam=#exam",
new { exam }).ToList();
But ultimately, I think I'd prefer a different db schema here...
there would be no need for a dynamic query, if those tables were normalized. (check your design)
if you really want to do this dynamically, you'll need an expression tree that handles the select part of your query ... here you can find some more details about a dynamic query lib that can handle that expression tree generation for you (you can provide a string like "new(p1,p2,p3)" and that gets translated to an expression tree)
Here you don't need to use linq, you can do it with logic
Now just get Num_Subjects like for unit1 = 6
DataTable dt = [whole_table];
int counter = Num_Subjects + 1; //7
string colName = "P" + counter.ToString(); //P7
while(dt.Columns.Contains(colName))
{
dt.Columns.Remove(colName);
colName = "P" + (++counter).ToString()
}
At last you we get a table upto P6 columns rest of columns will be deleted.

Include conditional checking in query with LINQ to SQL

Suggestion either in C# or VB.NET are welcome.
Table relationship:
Student 1:N TimeSheet (FK StudentId)
TimeSheet 1:N TimeRecord (FK TimeSheetId)
Dim query = From s In db.Students _
Let pair = (From ts In db.TimeSheets _
Join tr In db.TimeRecords On tr.TimeSheetId Equals ts.TimeSheetId _
Where ts.IsArchive = False And ts.IsCompleted = False _
Group By key = New With {ts.TimeSheetId, ts.StudentId} Into TotalHour = Sum(tr.BonusHour)) _
From part In pair _
Where part.key.StudentId = s.StudentId _
Select New With {.StudentId = s.StudentId, .AssignedId = s.AssignedId,.TotalTime = part.TotalHour}
Here's the result of the query:
734 -- 159 : 9 hrs 35 mm 28 sec
2655 -- 160 : 93 hrs 33 mm 50 sec
1566 -- 161 : 37 hrs 23 mm 53 sec
3114 -- 162 : 25 hrs 0 mm 21 sec
Wanted result of query:
733 -- 158 : 0 hr 0mm 0 sec
734 -- 159 : 9 hrs 35 mm 28 sec
736 -- 169 : 0 hrs 0mm 0sec
2655 -- 160 : 93 hrs 33 mm 50 sec
1566 -- 161 : 37 hrs 23 mm 53 sec
3114 -- 162 : 25 hrs 0 mm 21 sec
2165 -- 189 : 0 hr 0 mm 21 sec
There are some TimeSheet that have no TimeRecord, which I need to select as well. How can I select all of them to make selection like above wanted result? I'm thinking of how I can include some condtion
checking in the query to see if this TimeSheet has no TimeRecord then no need to Sum(tr.BonusHour) just assign TotalHour to zero. I don't know it's right way to go.
Any sugestion is welcome.
You can try doing something like this with the Sum (C#):
Sum(tr.BonusHour ?? 0)
which would be the same as
Sum(tr.BonusHour != null ? tr.BonusHour : 0)
I am not sure what type your BonusHour has, so you would use zero-correspondent object of this type instead of the 0 in the sample.

Categories

Resources