LINQ - many to many - linq

I have 2 collections - invitedUserAllowedTimes and meeting.AllowedTimes. Collection invitedUserAllowedTimes has collection invitedUserAllowedTimes.Times.
Collection invitedUserAllowedTimes.Times has values TimeID = 1, TimeID = 2, TimeID = 3, TimeID = 4, TimeID = 5, TimeID = 6.
Collection meeting.AllowedTimes has values TimeID = 2, TimeID = 3, TimeID = 4.
I want to select from invitedUserAllowedTimes all records, which has all meeting.AllowedTimes TimeIDs.
I try to do following:
var times = (
from i in invitedUserAllowedTimes
where i.Times.All(p => meeting.AllowedTimes.Any(k=>k.TimeID == p.TimeID))
select i).ToList();
but get no records. Why? What is incorrect in my code?

It's not returning anything because you're asking it to return all invitedUserAllowedTimes where all of its times are in meeting.AllowedTimes. So your example won't return it because meeting.AllowedTimes doesn't have TimeID 1, 5, or 6.
Instead you need to do this:
var times = (
from i in invitedUserAllowedTimes
where meeting.AllowedTimes.All(k=> i.Times.Contains(k.TimeID))
select i).ToList();
Or, using extension methods:
var times = invitedUserAllowedTimes.Where(i => meeting.AllowedTimes.All(k => i.Times.Contains(k.TimeID)).ToList();

Try this:
var times = (from i in invitedUserAllowedTimes
where meeting.AllowedTimes.All(k => i.Times.Contains(k.TimeID))
select i).ToList();

Related

How to loop cy.task according to the result

I'm testing the CRUDs for a page in my application, where a registry requires an unique ID as a 5 digit number to be successfully created.
I would like to get a random available ID of that table to use in the tests, that can be achieved with the following sql query:
cy.task(
'sqlQuery',
`select count(*) as "count" from clients where client_id = '${
Math.floor(Math.random() * 90000) + 10000
}'`
)
The point is that the random number perhaps is not available to be used as the ID, so i would need to loop this same task until the generated number is available:
cy.task(
'sqlQuery',
`select count(*) as "count" from clients where client_id = '${
Math.floor(Math.random() * 90000) + 10000
}'`
).then((result: any) => {
if (result.rows[0].count === 0) {
// My code to submit the form with the generated number
// break the loop
} else {
// Repeat all of this (where i'm asking for help)
}
})
If count returns 0 it means it's there's no registry using it, otherwise it's not available.
I guess the final solution could be using some while loop, but I found this way would be more clear to you all know what i'm needing.
I tried some approachs like this, but just discovery that its impossible to assign a new value to a variable inside the .then block, so it seems like i did an endless loop.
let available = false
do {
cy.task(
'sqlQuery',
`select count(*) as "count" from clients client_id = '${
Math.floor(Math.random() * 90000) + 10000
}'`
).then((result: any) => {
if (result.rows[0].count === 0) {
// Code to submit the form with the generated number
available = true
}
})
} while (available === false)
Ask SQL what ids are present and check the random one against those?
Something like this:
cy.task('sqlQuery', 'select client_id from clients')
.then((result: any) => {
const ids: string[] = result.rows;
function getNewId(trys = 0) {
if (trys > 1000) throw new Error('failed')
const newId = Math.floor(Math.random() * 90000) + 10000
if (ids.includes(newId)) {
return getNewId(++trys)
}
return newId
}
const newId = getNewId()
cy.wrap(newId).as('newId')
})
Update
Changed to a recursive javascript function, as I found when testing .should() it does not re-evaluate Math.floor(Math.random() * 90000) + 10000
It's been a while since I did some SQL, but maybe this correlated subquery is more efficient
SELECT last + 1 as newId FROM (
SELECT MAX(id) as last FROM clients
)
You can use a query like this to get 3 unused IDs for your tests
MySQL:
SELECT a.id+1 as 'ids'
FROM clients a
WHERE
NOT EXISTS (SELECT * FROM clients b WHERE a.id+1 = b.id) AND
a.id+1 < 100000
ORDER BY a.id
LIMIT 3
Oracle 11:
SELECT a.id+1 as ids
FROM clients a
WHERE
NOT EXISTS (SELECT * FROM clients b WHERE a.id+1 = b.id) AND
a.id+1 < 10000 AND
rownum <= 3
ORDER BY a.id;
Oracle 12:
SELECT a.id+1 as ids
FROM clients a
WHERE
NOT EXISTS (SELECT * FROM clients b WHERE a.id+1 = b.id) AND
a.id+1 < 10000
ORDER BY a.id
FETCH FIRST 3 ROWS ONLY;
This will search for unused IDs checking always the next ID, limiting it to 3 rows (you can limit the amount you need) to improve performance. And only available IDs, under 100000 (has only 5 digits)
For example:
Your table has de IDs (1, 3, 5, 6, 7, 9, 10)
This query will check if the IDs (2, 4, 6, 8, 10, 11) exist in the table. If it doesnt exists, it will return. So this example will return (2, 4, 8)

SSRS How to get the first and last values of a matrix row group?

I basically have the screenshot below as my layout.
My matrix columns are DCG1 and DCG2.
At the end of the Matrix I have a Total Group, which works just find. But I want to find the difference between my first and last value of the group. I've tried everything from ReportItems! to values. I cannot get SSRS to recognize these values.
So basically in the screen shots below. Screen shot 1 is the matrix structure. I have a column group called Test1, I want the first Value of Test1 and the last Value of Test 1 and place that in the Red box.
In screenshot 2, you can see the values i want to compare. The table groupings are named the same as the column + group. So dcs1group/dcs2group
Okay here is the DDL and DML for the datasource
http://pastebin.com/1ySN701D
The pastebin has been removed. Why, not sure so here it is below.
IF EXISTS
(SELECT [name]
FROM tempdb.sys.tables
WHERE [name] LIKE '%tmpHoldingTable%')
BEGIN
DROP TABLE #tmpHoldingTable;
END;
CREATE TABLE #tmpHoldingTable
(
dcs1 NVARCHAR (50),
dcs2 NVARCHAR (50),
Total DECIMAL (10, 2),
Test1 NVARCHAR (50)
)
INSERT INTO #tmpHoldingTable (dcs1,
dcs2,
Total,
Test1)
VALUES ('Contract',
'Breach of Contract',
500.00,
'01/01/2013-12/31/2013'),
('Contract',
'Breach of Contract',
300.00,
'01/01/2014-12/31/2014'),
('Employment',
'Discrimination',
500.00,
'01/01/2013-12/31/2013'),
('Employment',
'Discrimination',
300.00,
'01/01/2014-12/31/2014'),
('Employment',
'Research',
500.00,
'01/01/2013-12/31/2013'),
('Employment',
'Research',
300.00,
'01/01/2014-12/31/2014')
SELECT * FROM #tmpHoldingTable;
Yes, this is possible, but as you can see it is a bit complicated.
To make this a more generic answer, I have created my own DataSet, with simplified columns but more data:
select grp = 1, val = 100, dt = cast('01-jan-2015' as date)
union all select grp = 1, val = 110, dt = cast('01-jan-2015' as date)
union all select grp = 1, val = 200, dt = cast('02-jan-2015' as date)
union all select grp = 1, val = 210, dt = cast('02-jan-2015' as date)
union all select grp = 1, val = 300, dt = cast('03-jan-2015' as date)
union all select grp = 1, val = 310, dt = cast('03-jan-2015' as date)
union all select grp = 1, val = 400, dt = cast('04-jan-2015' as date)
union all select grp = 1, val = 410, dt = cast('04-jan-2015' as date)
union all select grp = 1, val = 500, dt = cast('05-jan-2015' as date)
union all select grp = 1, val = 510, dt = cast('05-jan-2015' as date)
union all select grp = 2, val = 220, dt = cast('02-jan-2015' as date)
union all select grp = 2, val = 230, dt = cast('02-jan-2015' as date)
union all select grp = 2, val = 320, dt = cast('03-jan-2015' as date)
union all select grp = 2, val = 330, dt = cast('03-jan-2015' as date)
union all select grp = 2, val = 420, dt = cast('04-jan-2015' as date)
union all select grp = 2, val = 430, dt = cast('04-jan-2015' as date)
Note that each grp / dt combination has two values, and that grp 1 is over a longer range for dt than grp 2.
I have created a simple Matrix based on this:
Since you are using SQL Server 2012, you can use the LookupSet function to get the First/Last values per row group.
The expression in the First row group TextBox is:
=Code.SumLookup(
LookupSet(
First(Fields!dt.Value, "grp").ToString & Fields!grp.Value.ToString
, Fields!dt.Value.ToString & Fields!grp.Value.ToString
, Fields!val.Value
, "DataSet1"
)
)
Based on my sample data, this is giving my required results:
Note that the second grp row has a narrower range than the first, but its first/last columns are independent for each group so are correct within each grp.
There are quite a few things going on here.
Custom code for aggregation of LookUpSet result
The LookupSet expression is wrapped in a Code.SumLookup custom function:
Function SumLookup(ByVal items As Object()) As Decimal
If items Is Nothing Then
Return Nothing
End If
Dim suma As Decimal = New Decimal()
suma = 0
For Each item As Object In items
suma += Convert.ToDecimal(item)
Next
Return suma
End Function
This is taken from the answer at this SO question.
This assumes that each matrix cell can be the sum of multiple values, so this needs to be summed up. LookupSet returns an array of values, which is aggregated by Code.SumLookup.
Details for LookupSet
Next, the LoopupSet expression itself:
LookupSet(
First(Fields!dt.Value, "grp").ToString & Fields!grp.Value.ToString
, Fields!dt.Value.ToString & Fields!grp.Value.ToString
, Fields!val.Value
, "DataSet1"
)
LookupSet takes the following parameters:
LookupSet(source_expression, destination_expression, result_expression, dataset)
In our expression, we want get all values from DataSet1 that match the first dt in the current grp scope.
For source_expression I use:
First(Fields!dt.Value, "grp").ToString & Fields!grp.Value.ToString
This gets the first dt in the row scope ("grp" is the name of the row group), then appends this to the current grp. This creates an expression to match to a similar expression when seeking in DataSet1.
i.e. destination_expression:
Fields!dt.Value.ToString & Fields!grp.Value.ToString
Finally, we specify we want Fields!val.Value as the result_expression and DataSet1 as the dataset parameter.
All matching Fields!val.Value values in DataSet1 are constructed into an array by LookupSet, then aggregated by Code.SumLookup.
Update expression for Last values
The expression for the Last TextBox is practically the same; just change First to Last:
=Code.SumLookup(
LookupSet(
Last(Fields!dt.Value, "grp").ToString & Fields!grp.Value.ToString
, Fields!dt.Value.ToString & Fields!grp.Value.ToString
, Fields!val.Value
, "DataSet1"
)
)
Get the Difference
Finally, to get the difference of these, simply subtract one expression from the other in the Difference TextBox, or even reference the ReportItems values:
=ReportItems!Last.Value - ReportItems!First.Value
Where Last and First are the names of the TextBoxes.
Conclusion
Obviously you will need to update for your specific case, but you can see that this can be done.
Is it worth doing this in your report? You can see there are many steps involved, and in general would be easier to address when generating the DataSet. But, if that is not an option hopefully this LookupSet approach is useful.
AFAIK this is not possible in SSRS alone. Believe me I've tried. Fortunately you have a SQL datasource so I would resolve this requirement there where you have (almost) unlimited powers to shape and manipulate data.
For example I would replace your final select with:
; WITH CTE_Base AS (
SELECT * FROM #tmpHoldingTable
)
, CTE_Test1 AS (
SELECT Test1
, ROW_NUMBER () OVER ( ORDER BY Test1 ) AS Column_Number_Test1
FROM CTE_Base
GROUP BY Test1
)
SELECT CTE_Base.*
, CTE_Test1.Column_Number_Test1
, CASE WHEN CTE_Test1.Column_Number_Test1 = 1
THEN Total
WHEN CTE_Test1.Column_Number_Test1 =
( SELECT MAX ( Column_Number_Test1 ) FROM CTE_Test1 )
THEN 0 - Total
ELSE 0
END AS [Difference]
FROM CTE_Base
INNER JOIN CTE_Test1
ON CTE_Base.Test1 = CTE_Test1.Test1
This adds a [Difference] column with a copy of [Total] for the 1st column and 0 - [Total] for the last column.
The SQL could probably be made more efficient, but hopefully breaking it into CTEs is easier to follow.
Then in the SSRS Designer you can add a [Difference] column outside the [Test1] column group and let it sum (default).
BTW your test data seems a bit simplistic - it will only produce 2 columns and all cells have values. But its great you posted DDL & DML - it made it easy to extend the data and code and test this.

How can I fetch every row where column is not in (array of values) with Doctrine?

I'm trying to accomplish something similar to the following SQL, but using the Doctrine API.
SELECT * FROM table_name WHERE column_name NOT IN (1, 2, 3);
I was thinking of something like this:
$entityManager->getRepository($entity)->findBy(array('ID' => array('NOT IN' => array(1, 2, 3))));
... How far am I?
You can do this with a DQL:
$result = $entityManager->createQuery("SELECT e FROM $entity e
WHERE e.ID NOT IN (:ids)")
->setParameter('ids', array(1, 2, 3), \Doctrine\DBAL\Connection::PARAM_INT_ARRAY)
->getResult();
Passing arrays as parameters is supported since Doctrine version 2.1.

query each month record in the table by linq

I have a datatable named testable, it has two columns id(primary key, int) and time(datetime). I want to calculate the number of records of every specific month in the table. For example, there are 5 rows in the table,
Id datetime(d/m/y)
1 12/3/2011
2 15/3/2011
3 4/4/2011
4 1/8/2011
5 19/12/2011
How to write a Linq query to query out the record like this,
Id datetime count
1. 1/2011 0
2. 2/2011 0
3. 3/2011 2
4. 4/2011 1
5. 5/2011 0
6. 6/2011 0
7. 7/2011 0
8. 8/2011 1
9. 9/2011 0
10. 10/2011 0
11. 11/2011 0
12. 12/2011 1
I have written a query statement like this,
var query = from c in testtable.AsEnumerable()
group c by new
{
years = Convert.ToDateTime(c.Field<string>("Posted")).Year,
months = Convert.ToDateTime(c.Field<string>("Posted")).Month
}
into d
orderby d.Key.years,d.Key.months
select new
{
Date = String.Format("{0}/{1}",d.Key.months,d.Key.years),
Count = d.Count()
};
But it only queries out the month 3/4/8/12, it can’t query out other month records.
Anyone can help?
You need to generate a sequence of all dates and left join your existing query with that sequence.
var allMonths = Enumerable.Range(1, 12)
.Select(i => String.Format("{0}/{1}", i, "2011"));
var query = new[]
{
new{ Date= "3/2011" , Count = 2},
new{ Date= "4/2011" , Count = 1},
new{ Date= "8/2011" , Count = 1},
new{ Date= "12/2011", Count = 1},
};
var query2 = from month in allMonths
join date in query on month equals date.Date into g
from date in g.DefaultIfEmpty()
select new
{
Date = month,
Count = (date == null) ? 0 : date.Count
};
foreach (var q in query2)
{
Console.WriteLine(q);
}

Translate SQL query without FROM clause to LINQ

How to translate query like "select 1, 2" (i.e. without FROM clause) to LINQ statement?
Thanks!
I need to get permissions for a set of user groups. In SQL it looks like
SELECT *
FROM Permission p
INNER JOIN (SELECT GroupID
FROM [Group]
UNION ALL
SELECT 555) AS g
ON (g.GroupID = p.GroupID)
In my case I need to programmatically add a certain code instead "555". I wouldn't like to write special SQL function for that.
I guess you just want to create an anonymous type
var anonymous = new { Column1 = 1, Column2 = 2 };
Edit - Based on Comments
Depending on what your Select projection is you could do something simple like this:
If it is a Int:
var query = (from per in context.permissions
select per).AsEnumerable()
.Concat( new int[] { 1, 2 });
If it is a 'Class'
var query = (from per in context.permissions
select per).AsEnumerable()
.Concat(new CustomClass[]
{
new CustomClass()
{
Prop1= 1
},
}
);
You could also change .Concat to .Union
Why do you need this to be linq?
var numbers = new int[] { 1, 2 };
I suppose
var numbers = Enumerable.Range(1,2);

Resources