Read IDataReader on a GROUP BY MySQL query - c#

I have a table "nesting_bar_detail", that I read like that in my C# code :
public List<RepereNest> SelectListRepereNestInMeb(string query)
{
List<RepereNest> list = new List<RepereNest>();
if (this.OpenConnection() == true)
{
IDataReader dataReader = ExecuteReader(query);
while (dataReader.Read())
{
RepereNest det = new RepereNest();
det.ID=(long)dataReader["ID"];
det.IdDetail=(long)dataReader["ID_DETAIL"];
det.IdNesting=(long)dataReader["ID_NESTING"];
det.Name = (string)dataReader["NAME"];
det.Quantity = (int)dataReader["QUANTITY"];
list.Add(det);
}
this.CloseConnection();
}
return list;
}
If I make a simple query, as here, all is working fine
SELECT * FROM nesting_bar_detail WHERE NAME='TITI'
But when I want to group the results, I make the following request :
SELECT ID,ID_DETAIL,ID_NESTING, NAME, SUM(QUANTITY) AS QUANTITY GROUP BY ID_DETAIL,ID_NESTING ORDER BY ID_NESTING
But then I have an error on the lines where I "calculate" the field (in that case on the line det.Quantity = (int)dataReader["QUANTITY"];, that is a SUM)
Error "The specified cast is invalid"
I don't understand if this my SQL request that is not correct, or why the returned value type is not recognized ?
Edit :
Here is the data I have inside database :
+-------+-----------+------------+------+----------+
| ID | ID_DETAIL | ID_NESTING | NAME | QUANTITY |
+-------+-----------+------------+------+----------+
| 10754 | 10 | 58 | TITI | 2 |
+-------+-----------+------------+------+----------+
| 10755 | 11 | 59 | TITI | 3 |
+-------+-----------+------------+------+----------+
| 10756 | 11 | 59 | TITI | 4 |
+-------+-----------+------------+------+----------+
And here is Expected result :
+-------+-----------+------------+------+----------+
| ID | ID_DETAIL | ID_NESTING | NAME | QUANTITY |
+-------+-----------+------------+------+----------+
| 10754 | 10 | 58 | TITI | 2 |
+-------+-----------+------------+------+----------+
| 10755 | 11 | 59 | TITI | 7 |
+-------+-----------+------------+------+----------+

Aggregate (GROUP BY) Function Descriptions
"The SUM() and AVG() functions return a DECIMAL value for exact-value arguments (integer or DECIMAL), and a DOUBLE value for approximate-value arguments (FLOAT or DOUBLE)."
In your C# code you're trying to cast the resulting DECIMAL value of SUM(QUANTITY) as an int

Related

StepArgumentTransformation is not getting hit

I have a scenario outline which contains scenarios which makes GET requests to a oData web API to get some data from it. Scenario
validate whether data returned from API is according to filters and in right order. Order by clause is built from table provided in the scenario
Scenario Outline: Validate that data from API call for a given user is according to filters provided
Given for the user id of 101
Given default filters for GET request
Given the result multicolumn order direction is <firstColumn> <firstOrderby> then <secondColumn> <secondOrderby>
And following is unordered list of securities
| securityID | attribute1 | attribute2 | attribute3 | attribute4 |
| 16654 | active | 0 | pending | 33 |
| 16655 | active | 0 | pending | 33 |
| 16656 | active | 0 | pending | 33 |
| 16657 | active | 0 | pending | 33 |
| 16658 | inactive | 4 | pending | 33 |
| 16659 | active | 0 | pending | 33 |
| 16660 | active | 0 | pending | 33 |
| 16661 | active | 0 | pending | 33 |
| 16662 | active | 0 | pending | 33 |
| 16663 | inactive | 0 | pending | 33 |
| 16664 | inactive | 2 | pending | 33 |
When I invoke the API GET
Then the SecAPI should return HTTP <statusCode>
And the response securities should be in expected order in each <sampleName> with matching fields and record count of 11
Examples:
| firstColumn | firstOrderby | secondColumn | secondOrderby | statusCode | sampleName |
| securityID | Asc | attribute2 | Desc | 200 | Asc-Desc |
| securityID | Asc | attribute2 | Asc | 200 | Asc-Asc |
| securityID | Desc | attribute2 | Asc | 200 | Desc-Asc |
| securityID | Asc | attribute2 | Desc | 200 | Asc-Desc |
| securityID | Asc | attribute2 | | 200 | Asc-Desc |
| securityID | | attribute2 | | 200 | Asc-Desc |
For above scenario outline, all is working fine except below given statement:
Given the result multicolumn order direction is <firstColumn> <firstOrderby> then <secondColumn> <secondOrderby>
for above statement, I have below step in steps.cs file
[Given(#"the result multicolumn (order direction is (.*) (.*) then (.*) (.*))")]
public void GivenTheResultOrderDirectionIs(StringWrapper orderBy)
{
//step code here
}
and following steptransformation to transform 4 arguments in given statement to proper oData orderBy clause:
[Binding]
public class CustomTransforms
{
[StepArgumentTransformation(#"order direction is <(\w+)> <(\w+)> then <(\w+)> <(\w+)>")]
public StringWrapper OrderByTransform(string column1, string column1Direction, string column2, string column2Direction)
{
string orderByClause;
//build clause here
return new StringWrapper(orderByClause);
}
}
problem is OrderByClauseTransform is never called. I am getting below exception:
Exception thrown: 'TechTalk.SpecFlow.BindingException' in TechTalk.SpecFlow.dll
An exception of type 'TechTalk.SpecFlow.BindingException' occurred in TechTalk.SpecFlow.dll but was not handled in user code
Parameter count mismatch! The binding method '.......GivenTheResultMulticolumnOrderDirectionIs(StringWrapper)' should have 5 parameters
Step transformations only receive a single argument. That's just how SpecFlow works. Once you have the full matched string, use a Regex to extract the desired pieces from that string. By declaring a constant for the regex pattern, you can reuse that in a Regex object as well as the [StepArgumentTransformation] attribute:
[Binding]
public class CustomTransforms
{
private const string OrderByPattern = #"order direction is (\w+) (\w+) then (\w+) (\w+)";
private static readonly Regex OrderByRegex = new Regex(OrderByPattern);
[StepArgumentTransformation(OrderByPattern)]
public StringWrapper OrderByTransform(string text)
{
var match = OrderByRegex.Match(text);
var column1 = match.Groups[1].Value;
var direction1 = match.Groups[2].Value;
var column2 = match.Groups[3].Value;
var direction2 = match.Groups[4].Value;
// Build your order by clause however you need to do it. For example, SQL:
var orderByClause = $"ORDER BY {column1} {direction1}, {column2} {direction2}";
return new StringWrapper(orderByClause);
}
}
Important: The < and > characters in your step argument transformation pattern are also messing things up. In your scenario, the <firstColumn> token is completely replaced by the current value in the examples table.
When the current example row is:
| firstColumn | firstOrderby | secondColumn | secondOrderby | statusCode | sampleName |
| securityID | Asc | attribute2 | Desc | 200 | Asc-Desc |
The step:
Given the result multicolumn order direction is <firstColumn> <firstOrderby> then <secondColumn> <secondOrderby>
is converted to this automatically:
Given the result multicolumn order direction is securityID Asc then attribute2 Desc
Notice that the < and > characters do not exist in the converted version of the step. The angle brackets are used to denote parameterized portions of a step that are replaced at run time by data from the examples table.

Check if id's in a comma-separated string match any id's in another string array

I have two tables in DB Master Setup Approval and Order Details and I want check On any Master Approval Setup, this purchase order will go on relying CostCenter.
Table Master Setup Approval:
|-------|---------|-------------|-------------|---------------|---------------------|
| ID | Name | CRG_COM_ID| CRG_BRN_ID |ApprovalTypeId |CostCenter(string) |
|-------|---------|-------------|-------------|---------------|---------------------|
| 1 | Setup1 | 1 | 1 | 1 | "1,2,5,7" |
|-------|---------|-------------|-------------|---------------|---------------------|
| 2 | Setup2 | 1 | 1 | 1 | "1,3,6" |
|-------|---------|-------------|-------------|---------------|---------------------|
Table OrderDetails :
|-------|---------|-------------|-------------|------------------|
| ID | Name | CRG_COM_ID| CRG_BRN_ID |CostCenterID(long)|
|-------|---------|-------------|-------------|------------------|
| 1 | Item1 | 1 | 1 | 1 |
|-------|---------|-------------|-------------|------------------|
| 2 | Item2 | 1 | 1 | 7 |
|-------|---------|-------------|-------------|------------------|
This is my code:
var orderDetails = db.OrderDetails.Where(c => c.OrderId == orderId);
var costc = orderDetails.Select(c => c.CostCenterId.Value).ToList().ConvertAll<string>(delegate (long i) { return i.ToString(); });
var ApprovalProcess_Count12 = db.MasterSetupApproval.Where(x =>
x.CRG_COM_ID == order.CompanyId &&
(x.CRG_BRN_ID == null || x.CRG_BRN_ID == order.BranchId) &&
x.ApprovalTypeId == (int)ApprovalTypes.PO &&
x.CostCenter.Split(',').Select(aee => aee).Any(val => costc.Contains(val))
).ToList();
I am getting the following error:
LINQ to Entities does not recognize the method 'System.String[] Split(Char[])' method, and this method cannot be translated into a store expression.
Output should be:
|-------|---------|-------------|-------------|---------------|---------------------|
| ID | Name | CRG_COM_ID| CRG_BRN_ID |ApprovalTypeId |CostCenter(string) |
|-------|---------|-------------|-------------|---------------|---------------------|
| 1 | Setup1 | 1 | 1 | 1 | "1,2,5,7" |
|-------|---------|-------------|-------------|---------------|---------------------|
Assuming you are working with a badly-designed DB (as pointed out by Crowcoder) that comma-separated values should not be present in a database, you may refer this to tackle your way through.
HTH!

SQL Get matching values from other table and show in main table

I'm trying to do some SQL in C# along with an Access Database. I have two tables. Main Table and a Second Table:
MAIN TABLE
DoubleValue | | | |
----------------------------------------
1,40 | | | |
1,80 | | | |
2,00 | | | |
1,80 | | | |
1,60 | | | |
1,60 | | | |
----------------------------------------
SECOND TABLE
DoubleValue | Points | Weight |
-------------------------------
1,00 | 100 | 2 |
1,20 | 98 | 2 |
1,40 | 96 | 2 |
1,60 | 94 | 2 |
1,80 | 92 | 2 |
2,00 | 90 | 2 |
-------------------------------
I need to find all matching rows in "SECOND TABLE" based on the column "Double Value". Then for the rows that matches I want to get the value in columns "Points" and "Weight" as well as multplie those two columns and create a columns with the name "Sum" and add all three columns to the "MAIN TABLE":
MAIN TABLE - RESULT/OUTPUT
DoubleValue | Points | Weight | Sum |
-------------------------------------
1,40 | 96 | 2 | 192 |
1,80 | 92 | 2 | 184 |
2,00 | 90 | 2 | 180 |
1,80 | 92 | 2 | 184 |
1,60 | 94 | 2 | 188 |
1,60 | 94 | 2 | 188 |
-------------------------------------
The "MAIN TABLE" doesn't need to actually have the new columns "physically" inserted. I would very much prefer if they could just be displayed in the output very much like "SELECT Points * Weight AS Sum" would produce where "Sum" would be displayed but not actually inserted in the table. BUT OK, if it needs to actually be inserted then I will go with that.
How can this be done?
You are looking for a simpler INNER JOIN statement. Please notice that Sum is wrapped as it is a Reserved word in most SQL variants. Please try to avoid naming items with these words.
SELECT m.DoubleValue
, s.Points
, s.Weight
, [Sum] = s.Points * s.Weight
FROM MainTable AS m
INNER JOIN SecondTable AS s ON m.DoubleValue = s.DoubleValue

Get record for each type with latest / bigger dates in C# DBML

I have a DB table which has some data as follows:
LINE | QTY | USERID | DATE
-----------------------------------------
1 | 5 | qb1 | 2015-03-02 11:23:25
2 | 1 | qb2 | 2015-03-02 18:24:03
3 | 3 | ch1 | 2015-03-03 05:38:49
1 | 2 | qb1 | 2015-03-03 08:47:02
2 | 4 | qb2 | 2015-03-03 14:01:31
3 | 2 | ch1 | 2015-03-03 21:11:53
1 | 4 | qb1 | 2015-03-04 09:34:04
2 | 5 | qb2 | 2015-03-04 15:29:27
3 | 1 | ch1 | 2015-03-04 19:28:33
As you can see I have only 3 unique LINE values in the DB. I require a LINQ query to select the latest record of every line. The date can be any date, I just need the latest status of the lines based on "DATE" field.
At the moment I am doing it very roughly something like this:
var line1 = db.GetTable<lnk_sts>().Where(x=> x.LINE== 1).OrderByDescending(x => x.DATE).FirstOrDefault();
Same for the other 2. What I Require is a list of lnk_sts with only the ones with a bigger date, in this case:
LINE | QTY | USERID | DATE
---------------------------------------
1 | 4 | qb1 | 2015-03-04 09:34:04
2 | 5 | qb2 | 2015-03-04 15:29:27
3 | 1 | ch1 | 2015-03-04 19:28:33
What you need to do is, group on Line and then take the first item in group after ordering in descending.
db.GetTable<lnk_sts>()
.GroupBy(x=>x.LINE)
.Select(x=>x.OrderByDescending(o=>o.DATE).FirstOrDefault())
.ToList();
First group by the line, then order by date and take the last item.
var result = db.GetTable<lnk_sts>().GroupBy(x=> x.LINE).Select(x => x.OrderBy(y => y.Date).Last())

linq: groupby with multiple nullable types

I have the following table:
| AppointID | UserID | AppointSet | AppointAttended | AppointCancelled | AppointRescheduled |
| 1 | 1 | 2/15/2011 | | 3/11/2011 | |
| 2 | 1 | 2/17/2011 | | | 3/11/2011 |
| 3 | 1 | 3/11/2011 | 3/11/2011 | | |
| 4 | 1 | 3/10/2011 | | 3/11/2011 |
|
What I'm trying to do is create the following output that counts the activity by day.
| Date | Set | Attended | Rescheduled | Cancelled |
| 3/10/2011 | 1 | | | |
| 3/11/2011 | 1 | 1 | 1 | 2 |
Note that I've defined the fields AppointAttended, AppointCancelled and AppointRescheduled as nullable because there might not be a date for these.
This is what I have so far and I'm struggling with the groupby because I need to group by multiple columns, and it's a nullable type, and I can't get the .Key to work! In other words, I feel really stuck with this:
var OutputMonthlyActivity = from appnt in MyDC.LeadsAppointments
where appnt.UserID == TheUserID
where (appnt.AppointSet.Month == TheDate.Month && appnt.AppointSet.Year == TheDate.Year) ||
(appnt.AppointAttended.Value.Month == TheDate.Month && appnt.AppointAttended.Value.Year == TheDate.Year) ||
(appnt.AppointRescheduled.Value.Month == TheDate.Month && appnt.AppointRescheduled.Value.Year == TheDate.Year) ||
(appnt.AppointCancelled.Value.Month == TheDate.Month && appnt.AppointCancelled.Value.Year == TheDate.Year)
group appnt by new { appnt.AppointSet, appnt.AppointRescheduled, appnt.AppointAttended, appnt.AppointCancelled } into daygroups
where daygroups.Count() > 1
select new ViewMonthlyActivityModel()
{
ViewDate = daygroups.Key,
CountTotalSetOnDay = (from c in daygroups
where c.AppointSet.Date == daygroups.Key
select c.AppointID).Count(),
TheDate is a datetime that's passed in as a parameter and that represents the 1st day of the month that's queried: 3/1/2011 for the month of the March for example.
I get "An anonymous type cannot have multiple properties with the same name" in the groupby statement and the .Key doesn't work so the grouping by day is not working.
If you have any suggestions, that'd be really appreciated.
Thanks.
You can try to explicitly set the right names of the properties of you anonymous type on which you group:
group appnt by new {
Set = appnt.AppointSet,
Rescheduled = appnt.AppointRescheduled,
Attended = appnt.AppointAttended,
Cancelled = appnt.AppointCancelled } into daygroups

Categories