Update Database to match array (Many to Many) - sql-server

I have 3 tables, lets call them Table1, Table2 and ManyMany table.
Table 1:
ID1 [PK],
Description1
Table 2:
ID2 [PK],
Description2
ManyMany:
ID1 [PK, FK],
ID2 [PK, FK]
I have 2 arrays:
Both of them use a PK from Table1 (ID1 == 3) and contain ID2 values.
Array1 [5,6,8] // from DB
Array2 [5,6,9] // from front-end
What I want to do is compare the 2 arrays and update the ManyMany to match Array2. So in this case record 'ID1 == 3 && ID2 == 8' must be deleted and record 'ID1 == 3 && ID2 == 9' must be added. But this will change. Can be multiple deletes and inserts etc..
How can I update the DB to match array2?
Are there a easy way to accomplish this?
It will be quite inefficient to delete all the records matching ID1 and inserting them again.
I am using ASP.NET Web API with LINQ and EntityFramework.

I've solved this problem using Linq's Except() extensions:
var toRemove = array1.Except(array2)
foreach(var item in toRemove) {
array1.Remove(item);
}
var toAdd = array2.Except(array1)
foreach(var item in toAdd) {
array1.Add(item);
}
//Do whatever you need to persist to the DB...

Related

Neo4j Condition Based Output

Question:
In Neo4j, I have relation (p:Person)-[:HAS_DOCUMNET]->(id:Identification)-[:HAS_DESCRIPTION]->(d:Document) and Required only 1 row data per person (personId,documentType and idNumber)
I required to develop query output on the basis of below priority condition
1)If documentType="Passport" is present then should come with personId and respected idNumber.(1st Priority)
2)If documentType="VoterCard" is present then should come with personeId and respected idNumber.(If Passport is not present)
3)If documentType="PanCard" is present then should come withe personId and respected idNumber.(If VoterId is not present)
Data Present like below:
(P1:Person)-[:HAS_Document]->('id1','id2','id3')->[:HAS_DESCRIPTION]->("Passpot","VoterCard",PanCard)`
(P2:Person)-[:HAS_Document]->('id4','id5')->[:HAS_DESCRIPTION]->("VoterCard","PanCard")`
(P3:Person)-[:HAS_Document]->('id6','id7','id8')->[:HAS_DESCRIPTION]->("PanCard","AadharCard","VoterCard")
(P4:Person)-[:HAS_Document]->('id9')->[:HAS_DESCRIPTION]->("PanCard")
Output should be like :
PName Doc.Type IDNumber
------- ----------- ---------
P1 "Passport" id1
P2 "VoterCard" id4
P3 "VoterCard" id8
P4 "PanCard" id9
I created below sample data as you described. The query involves a simple case when else and I collected the documents then check if passport, votercard and pancard exists in the collection.
(P1:Person)-[:HAS_Document]->("Passport","VoterCard","PanCard")
(P2:Person)-[:HAS_Document]->("VoterCard","PanCard")`
(P3:Person)-[:HAS_Document]->("PanCard","AadharCard","VoterCard")
(P4:Person)-[:HAS_Document]->("PanCard")
Create (p1:Person {Name: 'P1'})
Create (p2:Person {Name: 'P2'})
Create (p3:Person {Name: 'P3'})
Create (p4:Person {Name: 'P4'})
Create (d1:Document {Doc_Type: 'Passport'})
Create (d2:Document {Doc_Type: 'VoterCard'})
Create (d3:Document {Doc_Type: 'PanCard'})
Create (d4:Document {Doc_Type: 'AadharCard'})
Merge (p1)-[:HAS_DOCUMENT]-(d1)
Merge (p1)-[:HAS_DOCUMENT]-(d2)
Merge (p1)-[:HAS_DOCUMENT]-(d3)
Merge (p2)-[:HAS_DOCUMENT]-(d2)
Merge (p2)-[:HAS_DOCUMENT]-(d3)
Merge (p3)-[:HAS_DOCUMENT]-(d3)
Merge (p3)-[:HAS_DOCUMENT]-(d4)
Merge (p3)-[:HAS_DOCUMENT]-(d2)
Merge (p4)-[:HAS_DOCUMENT]-(d3)
Query:
MATCH (p: Person)-[: HAS_DOCUMENT]-(d:Document)
WHERE d.Doc_Type in ["Passport", "VoterCard", "PanCard"]
WITH p.Name as Name, collect(d.Doc_Type) as docType
RETURN Name,
CASE WHEN 'Passport' in docType THEN 'Passport'
WHEN 'VoterCard' in docType THEN 'VoterCard'
WHEN 'PanCard' in docType THEN 'PanCard'
ELSE NULL END as DocType
ORDER BY Name
Result:
╒══════╤═══════════╕
│"Name"│"DocType" │
╞══════╪═══════════╡
│"P1" │"Passport" │
├──────┼───────────┤
│"P2" │"VoterCard"│
├──────┼───────────┤
│"P3" │"VoterCard"│
├──────┼───────────┤
│"P4" │"PanCard" │
└──────┴───────────┘

Removing the repeating elements from a row in a squlite table

Please let me know if there is any query where in I remove the repeating entries in a row.
For eg: I have a table which has name with 9 telephone numbers:
Name Tel0 Tel1 Tel2 Tel3 Tel4 Tel5 Tel6 Tel7 Tel8
John 1 2 2 2 3 3 4 5 1
The final result should be as shown below:
Name Tel0 Tel1 Tel2 Tel3 Tel4 Tel5 Tel6 Tel7 Tel8
John 1 2 3 4 5
regards
Maddy
I fear that it will be more complicated to keep this format than to split the table in two as I suggested. If you insist on keeping the current schema then I would suggest that you query the row, organise the fields in application code and then perform an update on the database.
You could also try to use SQL UNION operator to give you a list of the numbers, a UNION by default will remove all duplicate rows:
SELECT Name, Tel FROM
(SELECT Name, Tel0 AS Tel FROM Person UNION
SELECT Name, Tel1 FROM Person UNION
SELECT Name, Tel2 FROM Person) ORDER BY Name ;
Which should give you a result set like this:
John|1
John|2
You will then have to step through the result set and saving each number into a separate variable (skipping those variables that do not exist) until the "Name" field changes.
Tel1 := Null; Tel2 := Null;
Name := ResultSet['Name'];
Tel0 := ResultSet['Tel'];
ResultSet.Next();
if (Name == ResultSet['Name']) {
Tel1 := ResultSet['Tel'];
} else {
UPDATE here.
StartAgain;
}
ResultSet.Next();
if (Name == ResultSet['Name']) {
Tel2 := ResultSet['Tel'];
} else {
UPDATE here.
StartAgain;
}
I am not recommending you do this, it is very bad use of a relational database but once implemented in a real language and debugged that should work.

Modeling a non-primary Key relationship

I am trying to model the following relationship with the intent of designing classes for EF code first.
Program table:
ProgramID - PK
ProgramName
ClusterCode
Sample data
ProgramID ProgramName ClusterCode
--------------------------------------
1 Spring A
2 Fall A
3 Winter B
4 Summer B
Cluster table:
ID
ClusterCode
ClusterDetails
Sample data:
ID ClusterCode ClusterDetails
---------------------------------
1 A 10
2 A 20
3 A 30
4 B 20
5 B 40
I need to join the Program table to the Cluster table so I can get the list of cluster details for each program.
The SQL would be
Select
from Programs P
Join Cluster C On P.ClusterCode = C.ClusterCode
Where P.ProgramID = 'xxx'
Note that for the Program table, ClusteCode is not unique.
For Cluster table, neither ClusterCode nor ClusterDetail is unique.
How would I model this so I can take advantage of navigation properties and code-first?
assuming you have mapped above two tables and make an association between them and you are using C#, you can use a simple join :
List<Sting> clustedDets=new ArrayList<String>();
var q =
from p in ClusterTable
join c in Program on p equals c.ClusterTable
select new { p.ClusterDetails };
foreach (var v in q)
{
clustedDets.Add(v.ClusterDetails);
}

Linq Query Condition for multiple row

I tried to solve one query from last 2 days but didn't.
It looks easy to understand but can't made.
There are two column in Table for example:
ResourceId || MappingId
1 2
1 3
2 2
2 4
3 2
3 4
4 2
4 5
5 2
5 4
This is one table which have two fields ResourceId and MappingId.
Now I want resourceId which have Mappingid {2,4}
Means answer must be ResourceId {2,3,5}
How can I get this answer in Linq Query?
Use Contains of collection. This method can be translated by Entity Framework into SQL IN operator:
int[] mappingIds = { 2, 4 };
var resources = from t in table
where mappingIds.Contains(t.MappingId)
select t.ResourceId;
Lambda syntax:
var resources = table.Where(t => mappingIds.Contains(t.MappingId))
.Select(t => t.ResourceId);
Generated SQL will look like:
SELECT [Extent1].[ResourceId]
FROM [dbo].[TableName] AS [Extent1]
WHERE [Extent1].[MappingId] IN (2,4)
UPDATE: If you want to get resources which have ALL provided mapping ids, then
var resources = from t in table
group t by t.ResourceId into g
where mappingIds.All(id => g.Any(t => t.Id == id))
select g.Key;
Entity Framework is able to translate this query into SQL, but it will not be that beautiful as query above.
IQueryable<int> resourceIds = table
// groups items by ResourceId
.GroupBy(item => item.ResourceId)
// consider only group where: an item has 2 as MappingId value
.Where(group => group.Select(item => item.MappingId).Contains(2))
// AND where: an item has 4 as MappingId value
.Where(group => group.Select(item => item.MappingId).Contains(4))
// select Key (= ResourceId) of filtered groups
.Select(group => group.Key);

Filtering data in LINQ

I have an observable collection which would be bound to the silverlight datagrid, where i need to display a particular row based on the data present in the OC
ID Name Status Desc Role
--------------------------------
1 ABC 500 des 50
1 ABC 500 des 55
2 XYZ 502 des 57
in the above table there are duplicate values, i need to filter them in such a way that when (status = 500) i need to pick the row which has role as 50. or if the (status = 501) i need to pick the row which has role as 55. In any instant the status would remain same for a particular ID. My final data should look like the one below.
ID Name Status Desc Role
---------------------------------
1 ABC 500 des 50
2 XYZ 502 des 57
It's not a fun query by any means. There may be a better answer, but this should get you started. The trick here is that you'll need to change your orderby clause to meet your needs. I couldn't tell from your question whether you were trying to pick the min Role value, or were trying to convey something else, but that orderby clause is where your custom logic for picking the right record goes.
var results =
from a in DataVals
group a by new {a.ID, a.Name, a.Status, a.Desc} into g
select new {
g.Key.ID,
g.Key.Name,
g.Key.Status,
g.Key.Desc,
Role = (
from b in DataVals
where b.ID == g.Key.ID
&& b.Name == g.Key.Name
&& b.Status == g.Key.Status
&& b.Desc == g.Key.Desc
orderby b.Role
select b.Role
).Take(1).FirstOrDefault()
};

Resources