I'm stucked with a linq query and I need a little bit of help.
I have the following tables
Table: Client
ClientId Name Age
(integer)
-------- ---------- -----
12635 John 23
87263 Derek 43
65237 Sarah 36
84735 Alice 28
Table: Action
Id Action ObjecId
(varchar)
-------- --------- ---------
202 Firefox 87263
203 Chrome 65237
204 Android 87263
205 Explorer 84735
206 Firefox 12635
My goal is to join both tables using ClientId and ObjectId fields. And for the Action table for each user I need to get only one record. If user has two records I need to get only the one with value='Android'
So the result with the above data should be:
Derek Android
Sarah Chrome
Alicie Explorer
John Firefox
I'm using the following approach.
var query = Set as IQueryable<Client>;
var actionQuery = Set as IQueryable<Action>
query= query.Join(actionQuery,
Client=> Client.ClientId.ToString(),
Action => Action.ObjectId.ToString(),
(Client, Action) => Client);
With the above I have a duplicate record for Derek, I need to get only one record for him, but I don't know how to do it. If a user has 2 records I need to get only the one with value='Android'.
Please, can you help me?
Thanks
If you need only a record where the ActionId is the highest, I'd do the following:
query = query.Join(actionQuery,
Client=> Client.ClientId.ToString(),
Action => Action.ObjectId.ToString(),
(Client, Action) => new { Client = Client, Action = Action })
.GroupBy(g => g.Client.Id)
.Select(g => g.OrderByDescending(gr => gr.Action.Id).First());
EDIT:
After the OP specified that if there are more actions for a particular client, one of those is always "Android" and this one must be chosen, I'm providing the following query:
query = query.Join(actions,
Client => Client.Id.ToString(),
Action => Action.ObjectId.ToString(),
(Client, Action) => new { Client = Client, Action = Action })
.GroupBy(g => g.Client.Id)
.Select(g => (g.Count() > 1) ? g.Where(gr => "Android".Equals(gr.Action.ActionDesc)).First() : g.First());
Related
I'm fetching rows from excel sheet in my application that holds attendance records from the bio metric machine. In order to get the best result i have to remove the redundant data. For that I have to manage check in and checkout timings at regular intervals. For instance, First check in time for entering, and then checkout time for lunch, then again check in for returning back, and last check out for going home. Meanwhile the rows in excel contains multiple check ins and check outs as the employee tends to do more that once for both.
I have managed to get records from excel and added to data table. Now for the sequence and sorting part I'm struggling to achieve my desired result. Below is my code.
protected void btnSaveAttendance_Click(object sender, EventArgs e)
{
try
{
if (FileUpload1.HasFile && Path.GetExtension(FileUpload1.FileName) == ".xls")
{
using (var excel = new OfficeOpenXml.ExcelPackage(FileUpload1.PostedFile.InputStream))
{
var tbl = new DataTable();
var ws = excel.Workbook.Worksheets.First();
var hasHeader = true; // adjust accordingly
// add DataColumns to DataTable
foreach (var firstRowCell in ws.Cells[1, 1, 1, ws.Dimension.End.Column])
tbl.Columns.Add(hasHeader ? firstRowCell.Text
: String.Format("Column {0}", firstRowCell.Start.Column));
// add DataRows to DataTable
int startRow = hasHeader ? 2 : 1;
for (int rowNum = startRow; rowNum <= ws.Dimension.End.Row; rowNum++)
{
var wsRow = ws.Cells[rowNum, 1, rowNum, ws.Dimension.End.Column];
DataRow row = tbl.NewRow();
foreach (var cell in wsRow)
row[cell.Start.Column - 1] = cell.Text;
tbl.Rows.Add(row);
}
var distinctNames = (from row in tbl.AsEnumerable()
select row.Field<string>("Employee Code")).Distinct();
DataRow[] dataRows = tbl.Select().OrderBy(u => u["Employee Code"]).ToArray();
var ss = dataRows.Where(p => p.Field<string>("Employee Code") == "55").ToArray();
}
}
}
catch (Exception ex) { }
}
The result i'm getting is:
Employee Code Employee Name Date Time In / Out
55 Alex 12/27/2018 8:59 IN
55 Alex 12/27/2018 8:59 IN
55 Alex 12/27/2018 13:00 OUT
55 Alex 12/27/2018 13:00 OUT
55 Alex 12/27/2018 13:48 IN
55 Alex 12/27/2018 13:49 IN
55 Alex 12/27/2018 18:08 OUT
And I want to have first In and then out and then in and then out. This would iterate four times to generate the result.
Expected result is:
Employee Code Employee Name Date Time In / Out
55 Alex 12/27/2018 8:59 IN
55 Alex 12/27/2018 13:00 OUT
55 Alex 12/27/2018 13:48 IN
55 Alex 12/27/2018 18:08 OUT
Can you try to do groupby in the result like below
ss=ss.GroupBy(x=>x.DateTime).ToArray();
Build a logic, if your result have 2 successive In/Out as a sample like below.
Here In I considered as field name
var tt;
for(int i=0;i<ss.Count();i++)
{
if(ss[i].In=="In" && (tt!=null || tt.LastOrDefault().In!="In"))
tt=ss[i];
else if(ss[i].In=="Out" && (tt!=null || tt.LastOrDefault().In!="Out"))
tt=ss[i];
}
I'm stuck on creating an algorithm as follows. I know this shouldn't be too difficult, but I simply can't get my head around it, and can't find the right description of this kind of pattern.
Basically I need a multi-level counter, where when a combination exist in the database, the next value is tried by incrementing from the right.
1 1 1 - Start position. Does this exist in database? YES -> Extract this and go to next
1 1 2 - Does this exist in database? YES -> Extract this and go to next
1 1 3 - Does this exist in database? YES -> Extract this and go to next
1 1 4 - Does this exist in database? NO -> Reset level 1, move to level 2
1 2 1 - Does this exist in database? YES -> Extract this and go to next
1 2 2 - Does this exist in database? NO -> Reset level 2 and 1, move to level 3
2 1 1 - Does this exist in database? YES -> Extract this and go to next
2 1 2 - Does this exist in database? YES -> Extract this and go to next
2 1 3 - Does this exist in database? NO -> Reset level 1 and increment level 2
2 2 1 - Does this exist in database? YES -> Extract this and go to next
2 2 2 - Does this exist in database? YES -> Extract this and go to next
2 2 3 - Does this exist in database? YES -> Extract this and go to next
2 3 1 - Does this exist in database? NO -> Extract this and go to next
3 1 1 - Does this exist in database? NO -> Extract this and go to next
3 2 1 - Does this exist in database? NO -> End, as all increments tried
There could be more than three levels, though.
In practice, each value like 1, 2, etc is actually a $value1, $value2, etc. containing a runtime string being matched against an XML document. So it's not just a case of pulling out every combination already existing in the database.
Assuming, the length of the DB key is known upfront, here's one way how it can be implemented. I'm using TypeScript but similar code can be written in your favorite language.
First, I declare some type definitions for convenience.
export type Digits = number[];
export type DbRecord = number;
Then I initialize fakeDb object which works as a mock data source. The function I wrote will work against this object. This object's keys are representing the the database records' keys (of type string). The values are simple numbers (intentionally sequential); they represent the database records themselves.
export const fakeDb: { [ dbRecordKey: string ]: DbRecord } = {
'111': 1,
'112': 2,
'113': 3,
'211': 4,
'212': 5,
'221': 6,
'311': 7,
};
Next, you can see the fun part, which is the function that uses counterDigits array of "digits" to increment depending on whether the record presence or absence.
Please, do NOT think this is the production-ready code! A) there are unnecessary console.log() invocations which only exist for demo purposes. B) it's a good idea to not read a whole lot of DbRecords from the database into memory, but rather use yield/return or some kind of buffer or stream.
export function readDbRecordsViaCounter(): DbRecord[] {
const foundDbRecords: DbRecord[] = [];
const counterDigits: Digits = [1, 1, 1];
let currentDigitIndex = counterDigits.length - 1;
do {
console.log(`-------`);
if (recordExistsFor(counterDigits)) {
foundDbRecords.push(extract(counterDigits));
currentDigitIndex = counterDigits.length - 1;
counterDigits[currentDigitIndex] += 1;
} else {
currentDigitIndex--;
for (let priorDigitIndex = currentDigitIndex + 1; priorDigitIndex < counterDigits.length; priorDigitIndex++) {
counterDigits[priorDigitIndex] = 1;
}
if (currentDigitIndex < 0) {
console.log(`------- (no more records expected -- ran out of counter's range)`);
return foundDbRecords;
}
counterDigits[currentDigitIndex] += 1;
}
console.log(`next key to try: ${ getKey(counterDigits) }`);
} while (true);
}
The remainings are some "helper" functions for constructing a string key from a digits array, and accessing the fake database.
export function recordExistsFor(digits: Digits): boolean {
const keyToSearch = getKey(digits);
const result = Object.getOwnPropertyNames(fakeDb).some(key => key === keyToSearch);
console.log(`key=${ keyToSearch } => recordExists=${ result }`);
return result;
}
export function extract(digits: Digits): DbRecord {
const keyToSearch = getKey(digits);
const result = fakeDb[keyToSearch];
console.log(`key=${ keyToSearch } => extractedValue=${ result }`);
return result;
}
export function getKey(digits: Digits): string {
return digits.join('');
}
Now, if you run the function like this:
const dbRecords = readDbRecordsViaCounter();
console.log(`\n\nDb Record List: ${ dbRecords }`);
you should see the following output that tells you about the iteration steps; as well as reports the final result in the very end.
-------
key=111 => recordExists=true
key=111 => extractedValue=1
next key to try: 112
-------
key=112 => recordExists=true
key=112 => extractedValue=2
next key to try: 113
-------
key=113 => recordExists=true
key=113 => extractedValue=3
next key to try: 114
-------
key=114 => recordExists=false
next key to try: 121
-------
key=121 => recordExists=false
next key to try: 211
-------
key=211 => recordExists=true
key=211 => extractedValue=4
next key to try: 212
-------
key=212 => recordExists=true
key=212 => extractedValue=5
next key to try: 213
-------
key=213 => recordExists=false
next key to try: 221
-------
key=221 => recordExists=true
key=221 => extractedValue=6
next key to try: 222
-------
key=222 => recordExists=false
next key to try: 231
-------
key=231 => recordExists=false
next key to try: 311
-------
key=311 => recordExists=true
key=311 => extractedValue=7
next key to try: 312
-------
key=312 => recordExists=false
next key to try: 321
-------
key=321 => recordExists=false
next key to try: 411
-------
key=411 => recordExists=false
------- (no more records expected -- ran out of counter's range)
Db Record List: 1,2,3,4,5,6,7
It is strongly recommended to read the code. If you want me to describe the approach or any specific detail(s) -- let me know. Hope, it helps.
I want to get the call details, from a second leg call, and insert them into my database.
Here is the scenario: an inbound call to a toll-free number is routed to second phone. So there are 2 legs, 1) the inbound call to the toll-free number and then 2) connection to the second number.
The code for getting the call details for the FIRST leg is:
get '/hangup' do
user_key = numbers.where(:number => params["To"]).join(:credentials, :user_id => :user_id).get(:user_key)
user_token = numbers.where(:number => params["To"]).join(:credentials, :user_id => :user_id).get(:user_token)
call_sid = params["CallSid"]
call_parent_sid = ["ParentCallSid"]
#sub_account_client = Twilio::REST::Client.new(user_key, user_token)
#subaccount = #sub_account_client.account
call = #subaccount.calls.get(call_sid)
call_sid = call.sid,
call_parent_sid = call.parent_call_sid,
phone_number_id = call.phone_number_sid,
call_from = call.from,
call_to = call.to,
call_start = call.start_time,
call_end = call.end_time,
call_duration = call.duration,
charged_duration = ((call_duration.to_f)/60).ceil
call_price = call.price
call_charged_price = (charged_duration * 0.07)
call_logs.insert(:call_sid => call_sid, :call_parent_sid => call_parent_sid, :phone_number_id => phone_number_id, :call_from => call_from, :call_to => call_to, :call_start => call_start, :call_end => call_end, :call_duration => call_duration, :charged_duration => charged_duration, :call_price => call_price, :call_charged_price => call_charged_price)
end
This works after hangup and the status_callback_url is '/hangup'. But how can I get the same details for the second leg of the call. I have tried as follows:
get '/receive' do
destination_number = numbers.where(:number => params["To"]).join(:users, :id => :user_id).get(:primary_number)
user_id = numbers.where(:number => params["To"]).join(:users, :id => :user_id).get(:id)
greeting_url = voicemail.where(:user_id => user_id).get(:voicemail_play_url)
resp = Twilio::TwiML::Response.new do |r|
r.Dial destination_number, :status_callback => '/hangup_second_leg', :status_callback_method => 'GET'
etc..
This effectively attempts to create a second status_callback_url which, needless to say, did not work.
So, how can I get the details of the second (or even third) leg of a call and bung it into my DB?
Twilio evangelist .....
Many thanks in advance.
Twilio developer evangelist at your service!
I just ran a quick test and the parameters you get back from the hangup callback should include a "CallSid" and a "DialedCallSid" which are the two legs of your call. You can get hold of the data via normal calls to the REST api:
get '/hangup' do
call_sid = params["CallSid"]
dialed_call_sid = params["DialedCallSid"]
#sub_account_client = Twilio::REST::Client.new(user_key, user_token)
#subaccount = #sub_account_client.account
inbound = #subaccount.calls.get(call_sid)
outbound = #subaccount.calls.get(dialed_call_sid)
# Update calls in database
end
Alternatively, the inbound call is the parent of all the other calls that take part within the context of the call. So you can get the details on all the child calls with the following api calls:
#subaccount.calls.list parent_call_sid: params["CallSid"]
# => [<Twilio::REST::Call>, ...]
Also, if you are getting a ParentCallSid parameter in your hangup, then you can use the above code to look up the parent call and child calls from that too.
Hope this helps, let me know if there's anything else I can help with.
We are using EF6.1 and dotConnect for Oracle.
Trying to debug why our development performs poorly in one of customers server, I turned on the DatabaseLogger Interceptor feature to get the queries executed in DB and try to improve them. One thing I've found is that in some queries there is some delay of seconds between the query has been executed and the connection has been closed. For example:
Connection opened at 17/06/2014 9:47:42 +02:00
SELECT
"top". (...)
FROM ( SELECT
"Project1". (...)
FROM ( SELECT
"Extent1". (...)
"Extent2". (...)
FROM (...)
WHERE (...)
) "Project1"
ORDER BY (...)
) "top"
WHERE ROWNUM <= 1
-- p__linq__0: '589' (Type = Int32, IsNullable = false)
-- Executing in 17/06/2014 9:47:43 +02:00
-- Completed in 288 ms with result: aj
Connection closed at 17/06/2014 9:47:51 +02:00
As you can see, there's a delay of many seconds. This query is runned many times, but the delay does not appear in every instance, others just have 2 or 3 seconds of delay, and others just none.
I don't really know where to begin to investigate. Is it something related to EF or to dotConnect Oracle? What job is done after the query has been executed and the connection closed?
EDIT: This is the code I'm using to retrieve the info from DB:
var users = db.USUARIO
.Where(x => x.COORDENADA.Any(c => c.LATITUD != 0 && c.LONGITUD != 0))
.OrderBy(x => x.NOMBRE).AsQueryable();
(...)
var list = users.ToList()
.Select(x => new
{
Usuario = x,
LastCoord = db.COORDENADA
.Include(c => c.TIPO)
.Where(c => c.USUARIOID == x.USUARIOID && c.LATITUD != 0 && c.LONGITUD != 0)
.OrderByDescending(c => c.FECHAHORAPDA)
.ThenBy(c => c.TIPO.RUTA).FirstOrDefault()
})
.Select(x => new ListItem
{
ID = x.LastCoord.COORDENADAID,
Marcadores = new List<COORDENADA>(new[] { x.LastCoord }),
Principal = x.Usuario.NOMBRE.ToTitleCase(),
Inferior1 = x.LastCoord.FECHAHORAPDA.ToString("dd/MM HH:mm"),
Color = x.LastCoord.TIPO.COLOR
});
The db.COORDENADA... is the query I exposed before.
i have three tables
cases,clients,attendance
in cases
id start_date end_date client_id status
1 2012-12-30 2013-01-30 1 new starts
2 2012-12-31 2013-01-31 2 probation
in clients
id Name dob gender status
1 TOM 1987-01-30 M A
2 JERRY 1985-01-31 F D
in attendance
id client_id date status
1 1 2013-01-30 A
2 1 2013-01-31 P
i need result like this
case_id case_start_date case_end_date client_id Name
att_date atte_status
1 2012-12-30 2013-01-30 1 TOM
2013-01-30,2013-01-31 A,P
is this possible? i'm a self learner and i don't have good idea in join query please any body help me....
try this..
$this->db->select('ca.*,ci.Name,a.date,a.status');
$this->db->from('cases'.' ca');
$this->db->join('clients'.' ci','ca.client_id=ci.id','left');
$this->db->join('attendance'.' a','a.client_id=ci.id','left');
return $this->db->get();
go through the user guide if u want to read more about join and active records...
Here's a very simple example to get you started with any number of join common fun for all
Construcor Code
Construct $joins as array:
$joins = array(
array(
'table' => 'table2',
'condition' => 'table2.id = table1.id',
'jointype' => 'LEFT'
),
);
Example function handling joins as an array:
public function get_joins($table, $columns, $joins)
{
$this->db->select($columns)->from($table);
if (is_array($joins) && count($joins) > 0)
{
foreach($joins as $k => $v)
{
$this->db->join($v['table'], $v['condition'], $v['jointype']);
}
}
return $this->db->get()->result_array();
}