How to end this loop / logically end pseudocode - loops

I'm writing a pseudocode program to read customer record, determine their account type, and then output their name and amount owed at the end. I wrote a program (almost done) I'm just not sure how to loop it until there are no more records left. Can you guys help me out? My output at the end is just supposed to be Customer Name and Amount Owed. Thanks.
read_customer_record
get num_of_records
get customer_name
get account_type
get num_basic_channels
get num_premium_channels
calculate_rate (calcR)
calculate_totals (calcT)
output(outp)
END
Calculate_rate (calcR)
IF account_type = personal
Basic_rateP = $5
Pre_rateP = $10
ELSE
Basic_rateB = $7.50
Pre_rateB = $12.50
END
Calculate_totals (calcT, calcR)
IF account_type = personal
total = (num_basic_channels * Basic_rateP) + (num_premium_channels * Pre_rateP)
ELSE
total = (num_basic_channels * Basic_rateB) + (num_premium_channels * Pre_rateB)
END
output (

You can do like this:
>>> Print Customer Name and Amount owed , till Customer Name is not equal to Null.
If I write the code in C++, it will look something like this.
for(i=0;CustomerName[i]!=NULL;i++) //Loop till there is some Customer Name exists
{
cout<<CustomerName[i]<<"\t"<<AmountOwed[i]; //Printing out the Data
}
It will stop when there will be no Customer Remaining and when there is not Customer , obviously there is no Amount Owed.

I think you just need to wrap a WHILE statement around your main routine. The way to do that depends on where you are reading the customer record from.
Case 1: In many contexts you can only tell that you have finished processing the input stream by attempting to read past the end. In that case your pseudocode might look like:
read_customer_record
while the previous read succeeded
get num_of_records
get customer_name
get account_type
get num_basic_channels
get num_premium_channels
calculate_rate (calcR)
calculate_totals (calcT)
output(outp)
read_customer_record
end
Case 2: In other contexts you can tell before a read whether there is something left to read from the input stream. In that case your pseudocode might look like:
while there are more customer records to process
read_customer_record
get num_of_records
get customer_name
get account_type
get num_basic_channels
get num_premium_channels
calculate_rate (calcR)
calculate_totals (calcT)
output(outp)
end

Related

Is this decision correct? PL/SQL

Can anyone help me with the following task:
Create a procedure SectionCount(instructor_ID) that, according to the instructor's ID, displays the numbers of those of its sections with the largest number of students enrolled. Display appropriate messages if an instructor with such an ID does not exist or if there are no sections to lead. Add a block to handle the necessary exceptions.
my solution is the following..whether it is correct:
CREATE OR REPLACE FUNCTION your_function_name(i_student_id NUMBER)
RETURN NUMBER AS v_sections_count NUMBER;
BEGIN
SELECT COUNT(SECTION_ID) into v_sections_count FROM ENROLLMENT WHERE STUDENT_ID = i_student_id;
IF v_sections_count > 3 THEN
RETURN -1;
ELSE
RETURN v_sections_count;
END IF;
EXCEPTION WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('An error occured.');
RETURN -2;
END;
A suggestion or two, if I may.
always use table's alias when referencing columns. In your case, that's only one table but - often you have to "fix" a query and add yet another table, and then you don't know which column belongs to which table and have to add aliases anyway.
try to use only one RETURN per function (two, if there's an exception handling section - as in your function) because you might do something wrong in code logic and RETURN (i.e. terminate further execution) although you didn't actually want to do that. Instead, add a new variable which will be used to "calculate" the return value (such as retval in code I posted); then return its value
DBMS_OUTPUT.PUT_LINE is OK for debugging; nobody else will ever see it, because end users won't call that function from SQL*Plus (or other tools which are capable of displaying that message). For example, it (DBMS_OUTPUT.PUT_LINE) won't raise error in Oracle Apex or Oracle Forms, but you won't see anything.
Also, add SQLERRM which will actually show you which error happened. Info "an error occurred" isn't very descriptive
So:
CREATE OR REPLACE FUNCTION your_function_name (i_student_id NUMBER)
RETURN NUMBER
AS
v_sections_count NUMBER;
retval NUMBER;
BEGIN
SELECT COUNT(e.section_id)
INTO v_sections_count
FROM enrollment e
WHERE e.student_id = i_student_id;
retval := CASE WHEN v_sections_count > 3 then -1
ELSE v_sections_count
END;
RETURN retval;
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('An error occured: ' || SQLERRM);
retval := -2;
RETURN retval;
END your_function_name ;

SQL Threadsafe UPDATE TOP 1 for FIFO Queue

I have a table of invoices being prepared, and then ready for printing.
[STATUS] column is Draft, Print, Printing, Printed
I need to get the ID of the first (FIFO) record to be printed, and change the record status. The operation must be threadsafe so that another process does not select the same InvoiceID
Can I do this (looks atomic to me, but maybe not ...):
1:
WITH CTE AS
(
SELECT TOP(1) [InvoiceID], [Status]
FROM INVOICES
WHERE [Status] = 'Print'
ORDER BY [PrintRequestedDate], [InvoiceID]
)
UPDATE CTE
SET [Status] = 'Printing'
, #InvoiceID = [InvoiceID]
... perform operations using #InvoiceID ...
UPDATE INVOICES
SET [Status] = 'Printed'
WHERE [InvoiceID] = #InvoiceID
or must I use this (for the first statement)
2:
UPDATE INVOICES
SET [Status] = 'Printing'
, #InvoiceID = [InvoiceID]
WHERE [InvoiceID] =
(
SELECT TOP 1 [InvoiceID]
FROM INVOICES WITH (UPDLOCK)
WHERE [Status] = 'Print'
ORDER BY [PrintRequestedDate], [InvoiceID]
)
... perform operations using #InvoiceID ... etc.
(I cannot hold a transaction open from changing status to "Printing" until the end of the process, i.e. when status is finally changed to "Printed").
EDIT:
In case it matters the DB is READ_COMMITTED_SNAPSHOT
I can hold a transaction for both UPDATE STATUS to "Printing" AND get the ID. But I cannot continue to keep transaction open all the way through to changing the status to "Printed". This is an SSRS report, and it makes several different queries to SQL to get various bits of the invoice, and it might crash/whatever, leaving the transaction open.
#Gordon Linoff "If you want a queue" The FIFO sequence is not critical, I would just like invoices that are requested first to be printed first ... "more or less" (don't want any unnecessary complexity ...)
#Martin Smith "looks like a usual table as queue requirement" - yes, exactly that, thanks for the very useful link.
SOLUTION:
The solution I am adopting is from comments:
#lad2025 pointed me to SQL Server Process Queue Race Condition which uses WITH (ROWLOCK, READPAST, UPDLOCK) and #MartinSmith explained what the Isolation issue is and pointed me at Using tables as Queues - which talks about exactly what I am trying to do.
I have not grasped why UPDATE TOP 1 is safe, and UPDATE MyTable SET xxx = yyy WHERE MyColumn = (SELECT TOP 1 SomeColumn FROM SomeTable ORDER BY AnotherColumn) (without Isolation Hints) is not, and I ought to educate myself, but I'm happy just to put the isolation hints in my code and get on with something else :)
Thanks for all the help.
My concern would be duplicate [InvoiceID]
Multiple print requests for the same [InvoiceID]
On the first update ONE row gets set [Status] = 'Printing'
On the second update all [InvoiceID] rows get set [Status] = 'Printed'
This would even set rows with status = 'draft'
Maybe that is what you want
Another process could pick up the same [InvoiceID] before the set [Status] = 'Print'
So some duplicates will print and some will not
I go with comments on use the update lock
This is non-deterministic but you could just take top (1) and skip the order by. You will tend to get the most recent row but it is not guaranteed. If you clear the queue then you get em all.
This demonstrates you can lose 'draft' = 1
declare #invID int;
declare #T table (iden int identity primary key, invID int, status tinyint);
insert into #T values (1, 2), (5, 1), (3, 1), (4, 1), (4, 2), (2, 1), (1, 1), (5, 2), (5, 2);
declare #iden int;
select * from #t order by iden;
declare #rowcount int = 1;
while (#ROWCOUNT > 0)
begin
update top (1) t
set t.status = 3, #invID = t.invID, #iden = t.iden
from #t t
where t.status = '2';
set #rowcount = ##ROWCOUNT;
if(#rowcount > 0)
begin
select #invID, #iden;
-- do stuff
update t
set t.status = 4
from #t t
where t.invID = #invID; -- t.iden = #iden;
select * from #T order by iden;
end
end
ATOMicity of a Single Statement
I think your code's fine as it is. i.e. Because you have a single statement which updates the status to printing as soon as the statement runs the status is updated; so anything running before which searches for print would have updated the same record to printing before your process saw it; so your process would pick a subsequent record, or any process hitting it after your statement had run would see it as printing so would not pick it up`. There isn't really a scenario where a record could pick it up whilst the statement's running since as discussed a single SQL statement should be atomic.
Disclaimer
That said, I'm not enough of an expert to say whether explicit lock hints would help; in my opinion they're not needed as the above is atomic, but others in the comments are likely better informed than me. However, running a test (albeit where database and both threads are run on the same machine) I couldn't create a race condition... maybe if the clients were on different machines / if there was a lot more concurrency you'd be more likely to see issues.
My hope is that others have interpreted your question differently, hence the disagreement.
Attempt to Disprove Myself
Here's the code I used to try to cause a race condition; you can drop it into LINQPad 5, select language C# Program, tweak the connectionstring (and optionally any statements) as required, then run:
const long NoOfRecordsToTest = 1000000;
const string ConnectionString = "Server=.;Database=Play;Trusted_Connection=True;"; //assumes a database called "play"
const string DropFifoQueueTable = #"
if object_id('FIFOQueue') is not null
drop table FIFOQueue";
const string CreateFifoQueueTable = #"
create table FIFOQueue
(
Id bigint not null identity (1,1) primary key clustered
, Processed bit default (0) --0=queued, null=processing, 1=processed
)";
const string GenerateDummyData = #"
with cte as
(
select 1 x
union all
select x + 1
from cte
where x < #NoRowsToGenerate
)
insert FIFOQueue(processed)
select 0
from cte
option (maxrecursion 0)
";
const string GetNextFromQueue = #"
with singleRecord as
(
select top (1) Id, Processed
from FIFOQueue --with(updlock, rowlock, readpast) --optionally include this per comment discussions
where processed = 0
order by Id
)
update singleRecord
set processed = null
output inserted.Id";
//we don't really need this last bit for our demo; I've included in case the discussion turns to this..
const string MarkRecordProcessed = #"
update FIFOQueue
set Processed = 1
where Id = #Id";
void Main()
{
SetupTestDatabase();
var task1 = Task<IList<long>>.Factory.StartNew(() => ExampleTaskForced(1));
var task2 = Task<IList<long>>.Factory.StartNew(() => ExampleTaskForced(2));
Task.WaitAll(task1, task2);
foreach (var processedByBothThreads in task1.Result.Intersect(task2.Result))
{
Console.WriteLine("Both threads processed id: {0}", processedByBothThreads);
}
Console.WriteLine("done");
}
static void SetupTestDatabase()
{
RunSql<int>(new SqlCommand(DropFifoQueueTable), cmd => cmd.ExecuteNonQuery());
RunSql<int>(new SqlCommand(CreateFifoQueueTable), cmd => cmd.ExecuteNonQuery());
var generateData = new SqlCommand(GenerateDummyData);
var param = generateData.Parameters.Add("#NoRowsToGenerate",SqlDbType.BigInt);
param.Value = NoOfRecordsToTest;
RunSql<int>(generateData, cmd => cmd.ExecuteNonQuery());
}
static IList<long> ExampleTaskForced(int threadId) => new List<long>(ExampleTask(threadId)); //needed to ensure prevent lazy loadling from causing issues with our tests
static IEnumerable<long> ExampleTask(int threadId)
{
long? x;
while ((x = ProcessNextInQueue(threadId)).HasValue)
{
yield return x.Value;
}
//yield return 55; //optionally return a fake result just to prove that were there a duplicate we'd catch it
}
static long? ProcessNextInQueue(int threadId)
{
var id = RunSql<long?>(new SqlCommand(GetNextFromQueue), cmd => (long?)cmd.ExecuteScalar());
//Debug.WriteLine("Thread {0} is processing id {1}", threadId, id?.ToString() ?? "[null]"); //if you want to see how we're doing uncomment this line (commented out to improve performance / increase the likelihood of a collision
/* then if we wanted to do the second bit we could include this
if(id.HasValue) {
var markProcessed = new SqlCommand(MarkRecordProcessed);
var param = markProcessed.Parameters.Add("#Id",SqlDbType.BigInt);
param.Value = id.Value;
RunSql<int>(markProcessed, cmd => cmd.ExecuteNonQuery());
}
*/
return id;
}
static T RunSql<T>(SqlCommand command, Func<SqlCommand,T> callback)
{
try
{
using (var connection = new SqlConnection(ConnectionString))
{
command.Connection = connection;
command.Connection.Open();
return (T)callback(command);
}
}
catch (Exception e)
{
Debug.WriteLine(e.ToString());
throw;
}
}
Other comments
The above discussion's really only talking about multiple threads taking the next record from the queue whilst avoiding any single record being picked up by multiple threads. There are a few other points...
Race Condition outside of SQL
Per our discussion, if FIFO is mandatory there are other things to worry about. i.e. whilst your threads will pick up each record in order after that it's up to them. e.g. Thread 1 gets record 10 then Thread 2 gets record 11. Now Thread 2 sends record 11 to the printer before Thread 1 sends record 10. If they're going to the same printer, your prints would be out of order. If they're different printers, not a problem; all prints on any printer are sequential. I'm going to assume the latter.
Exception Handling
If any exception occurs in a thread that's processing something (i.e. so the thread's record is printing) then consideration should be made on how to handle this. One option is to keep that thread retrying; though that may be indefinite if it's some fundamental fault. Another is to put the record to some error status to be handled by another process / where it's accepted that this record won't appear in order. Finally, if the order of invoices in the queue is an ideal rather than a hard requirement you could have the owning thread put the status back to print so that it or another thread can pick up that record to retry (though again, if there's something fundamentally wrong with the record, this may block up the queue).
My recommendation here is the error status; as then you have more visibility on the issue / can dedicate another process to dealing with issues.
Crash Handling
Another issue is that because your update to printing is not held within a transaction, if the server crashes you leave the record with this status in the database, and when your system comes back online it's ignored. Ways to avoid that are to include a column saying which thread is processing it; so that when the system comes back up that thread can resume where it left off, or to include a date stamp so that after some period of time any records with status printing which "timeout" can be swept up / reset to Error or Print statuses as required.
WITH CTE AS
(
SELECT TOP(1) [InvoiceID], [Status], [ThreadId]
FROM INVOICES
WHERE [Status] = 'Print'
OR ([Status] = 'Printing' and [ThreadId] = #ThreadId) --handle previous crash
ORDER BY [PrintRequestedDate], [InvoiceID]
)
UPDATE CTE
SET [Status] = 'Printing'
, [ThreadId] = #ThreadId
OUTPUT Inserted.[InvoiceID]
Awareness of Other Processes
We've mostly been focussed on the printing element; but other processes may also be interacting with your Invoices table. We can probably assume that aside from creating the initial Draft record and updating it to Print once ready for printing, those processes won't touch the Status field. However, the same records could be locked by completely unrelated processes. If we want to ensure FIFO we must not use the ReadPast hint, as some records may have status Print but be locked, so we'd skip over them despite them having the earlier PrintRequestedDate. However, if we want things to print as quickly as possible, with them being in order when otherwise not inconvenient, including ReadPast will allow our print process to skip the locked records and carry on, coming back to handle them once they're released.
Similarly another process may lock our record when it's at Printing status, so we can't update it to mark it as complete. Again, if we want to avoid this from causing a holdup we can make use of the ThreadId column to allow our thread to leave the record at status Printing and come back to clean it up later when it's not locked. Obviously this assumes that the ThreadId column is only used by our print process.
Have a dedicated print queue table
To avoid some of the issues with unrelated processes locking your invoices, move the Status field into its own table; so you only need to read from the invoices table; not update it.
This will also have the advantage that (if you don't care about print history) you can delete the record once done, so you'll get better performance (as you won't have to search through the entire invoices table to find those which are ready to print). That said, there's another option for this one (if you're on SQL2008 or above).
Use Filtered Index
Since the Status column will be updated several times it's not a great candidate for an index; i.e. as the record's position in the index jumps from branch to branch as the status progresses.
However, since we're filtering on it it's also something that would really benefit from having an index.
To get around this contradiction, one option's to use a filtered index; i.e. only index those records we're interested in for our print process; so we maintain a small index for a big benefit.
create nonclustered index ixf_Invoices_PrintStatusAndDate
on dbo.Invoices ([Status], [PrintRequestedDate])
include ([InvoiceId]) --just so we don't have to go off to the main table for this, but can get all we need form the index
where [Status] in ('Print','Printing')
Use "Enums" / Reference Tables
I suspect your example uses strings to keep the demo code simple, however including this for completeness.
Using strings in databases can make things hard to support. Rather than having status be a string value, instead use an ID from a related Statuses table.
create table Statuses
(
ID smallint not null primary key clustered --not identity since we'll likely mirror this enum in code / may want to have defined ids
,Name
)
go
insert Statuses
values
(0, 'Draft')
, (1,'Print')
, (2,'Printing')
, (3,'Printed')
create table Invoices
(
--...
, StatusId smallint foreign key references Statuses(Id)
--...
)

navision- looping through line nos in sales line

i am trying to retrieve the difference of qty and qts shipped for a sales order.
i am doing this through code.
setting range on sales line table fields and using findset does loop through all lines properly but while printing it gives the difference frm the last line.
clearing the variable is also not working.
i am new to NAV 2013 so not able to find out how to loop through all this lines so that it displays result properly.i tried using findfirst inside the if loop but no success.
You need to add to "Value", not overwrite it. (use +=, not :=)
CLEAR(Value);
SalesLine.RESET;
SalesLine.SETRANGE(SalesLine."Document No.","No.");
IF SalesLine.FINDSET THEN REPEAT
Value += SalesLine.Quantity - SalesLine."Quantity Shipped";
//MESSAGE('%1',Value);
UNTIL SalesLine.NEXT =0;
Try this code
local procedure DailyCalc(DailyLotNumber: Query DailyLotNumber): Decimal
var
SalesLine: Record "Sales Line";
NewRec: Decimal;
begin
SalesLine.SetRange("Document No.", DailyLotNumber.No_);
SalesLine.SetRange("Document Type", DailyLotNumber.Document_Type);
if SalesLine.FindSet() then begin
repeat
repeat
NewRec += (SalesLine.Quantity - SalesLine."Quantity Shipped") * SalesLine."Unit Price";
until SalesLine.Next() = 0;
exit(NewRec);
until SalesLine.Next() = 0;
end;
end;

Need to use information from one qry to dictate an action on another

Ok so this is going to sound a little complicated. I want to somehow put some kind of function that will divide a table value by two when its Policy number matches up with a policy number in another table.
Here is the query where I want that functions
SELECT
qryReinsuranceDPA1_izzy.POLICY_NO,
qryReinsuranceDPA1_izzy.PHASE_CODE,
qryReinsuranceDPA1_izzy.SUB_PHASE_CODE,
qryReinsuranceDPA1_izzy.SchedNP,
qryReinsuranceDPA1_izzy.ProdType,
Sum(qryReinsuranceDPA1_izzy.SumOfAMOUNT_INFORCE) AS SumOfSumOfAMOUNT_INFORCE,
Sum(qryReinsuranceDPA1_izzy.SumOfPUA_FACE) AS SumOfSumOfPUA_FACE,
Sum(qryReinsuranceDPA1_izzy.SumOfOYT_FACE) AS SumOfSumOfOYT_FACE, TotalDPA = sum(case when qryReinsuranceDPA1_izzy.[SumOfNetDefExtraAdj] Is Null then qryReinsuranceDPA1_izzy.[SumOfNetDefPremiumAdj] else qryReinsuranceDPA1_izzy.[SumOfNetDefPremiumAdj] +qryReinsuranceDPA1_izzy.[SumOfNetDefExtraAdj] end),
qryReinsuranceDPA1_izzy.SumOfGROSS_ANNLZD_PREM,
qryReinsuranceDPA1_izzy.SumOfStatNetPremium,
qryReinsuranceDPA1_izzy.[SumOfStatNetPremium]/qryReinsuranceDPA1_izzy.[SumOfGROSS_ANNLZD_PREM] AS NetToGrossRatio,
qryReinsuranceDPA1_izzy.NetvsGrossInd,
DPA_NetPrem = case when qryReinsuranceDPA1_izzy.[NetvsGrossInd]='Net' then sum(qryReinsuranceDPA1_izzy.[SumOfStatNetPremium]) else sum([qryReinsuranceDPA1_izzy].[SumOfGROSS_ANNLZD_PREM]) end,
qryPolicyListforNYDefPRemAsset_Re.ReinType AS ReinType,
Sum(qryPolicyListforNYDefPRemAsset_Re.ReinsAmount) AS SumOfReinsAmount,
qryPolicyListforNYDefPRemAsset_Re.[ReinsAmount]/(qryReinsuranceDPA1_izzy.[SumOfAMOUNT_INFORCE]+qryReinsuranceDPA1_izzy.[SumOfOYT_FACE]+qryReinsuranceDPA1_izzy.[SumOfPUA_FACE]) AS [Reins%],
qryPolicyListforNYDefPRemAsset_Re.ReinsStatRsv AS ReinsStatRsv,
Sum(qryPolicyListforNYDefPRemAsset_Re.SumOfGROSS_ANNLZD_PREM) AS ReinsPrem, qryReinsuranceDPA1_izzy.PAID_TO_DATE,
qryReinsuranceDPA1_izzy.VAL_DATE,
qryReinsuranceDPA1_izzy.ISSUE_DATE
FROM qryPolicyListforNYDefPRemAsset_Re RIGHT JOIN
qryReinsuranceDPA1_izzy
ON
qryReinsuranceDPA1_izzy.POLICY_NO = qryPolicyListforNYDefPRemAsset_Re.POLICY_NO
AND qryReinsuranceDPA1_izzy.PHASE_CODE = qryPolicyListforNYDefPRemAsset_Re.PHASE_CODE AND
qryReinsuranceDPA1_izzy.SUB_PHASE_CODE= qryPolicyListforNYDefPRemAsset_Re.SUB_PHASE_CODE
GROUP BY
qryReinsuranceDPA1_izzy.POLICY_NO,
qryReinsuranceDPA1_izzy.PHASE_CODE,
qryReinsuranceDPA1_izzy.SUB_PHASE_CODE,
qryReinsuranceDPA1_izzy.SchedNP,
qryReinsuranceDPA1_izzy.ProdType,
qryReinsuranceDPA1_izzy.SumOfGROSS_ANNLZD_PREM,
qryReinsuranceDPA1_izzy.SumOfStatNetPremium,
qryReinsuranceDPA1_izzy.[SumOfStatNetPremium]/qryReinsuranceDPA1_izzy.[SumOfGROSS_ANNLZD_PREM],
qryReinsuranceDPA1_izzy.NetvsGrossInd,
qryPolicyListforNYDefPRemAsset_Re.ReinType,
qryPolicyListforNYDefPRemAsset_Re.[ReinsAmount]/(qryReinsuranceDPA1_izzy.[SumOfAMOUNT_INFORCE]+qryReinsuranceDPA1_izzy.[SumOfOYT_FACE]+qryReinsuranceDPA1_izzy.[SumOfPUA_FACE]),
qryPolicyListforNYDefPRemAsset_Re.ReinsStatRsv,
qryReinsuranceDPA1_izzy.PAID_TO_DATE,
qryReinsuranceDPA1_izzy.VAL_DATE,
qryReinsuranceDPA1_izzy.ISSUE_DATE
GO
and this is the qry that contains the policy numbers that I want divided by 2 in the above qry.
SELECT
qryReinsuranceDPA1.POLICY_NO,
qryReinsuranceDPA1.PHASE_CODE,
qryReinsuranceDPA1.SUB_PHASE_CODE,
qryReinsuranceDPA1.ProdType,
TotalDPA = Sum(case when [SumOfNetDefExtraAdj] Is Null then [SumOfNetDefPremiumAdj] else [SumOfNetDefPremiumAdj] + SumOfNetDefExtraAdj end),
Sum(1) AS Expr1
FROM qryPolicyListforNYDefPRemAsset_Re RIGHT JOIN qryReinsuranceDPA1
ON
qryReinsuranceDPA1.POLICY_NO = qryPolicyListforNYDefPRemAsset_Re.POLICY_NO AND
qryReinsuranceDPA1.PHASE_CODE= qryPolicyListforNYDefPRemAsset_Re.PHASE_CODE AND
qryReinsuranceDPA1.SUB_PHASE_CODE = qryPolicyListforNYDefPRemAsset_Re.SUB_PHASE_CODE
GROUP BY qryReinsuranceDPA1.POLICY_NO,
qryReinsuranceDPA1.PHASE_CODE,
qryReinsuranceDPA1.SUB_PHASE_CODE,
qryReinsuranceDPA1.ProdType
HAVING (((Sum(1))<>1))
GO
quick example. Say that the Policy number 064543200 is located in the results of that second qry. I then want the number located in first qry in Total DPA assosciated with that Policy number to be divided by 2.
If this is still confusing please let me know and I will try to explain better. Both are views.

Linq - how get the minimum, if value = 0, get the next value

I have a test database which logs data from when a store logs onto a store portal and how long it stays logged on.
Example:
(just for visualizing purposes - not actual database)
Stores
Id Description Address City
1 Candy shop 43 Oxford Str. London
2 Icecream shop 45 Side Lane Huddersfield
Connections
Id Store_Ref Start End
1 2 2011-02-11 09:12:34.123 2011-02-11 09:12:34.123
2 2 2011-02-11 09:12:36.123 2011-02-11 09:14:58.125
3 1 2011-02-14 08:42:10.855 2011-02-14 08:42:10.855
4 1 2011-02-14 08:42:12.345 2011-02-14 08:50:45.987
5 1 2011-02-15 08:35:19.345 2011-02-15 08:38:20.123
6 2 2011-02-19 09:08:55.555 2011-02-19 09:12:46.789
I need to get various data from the database. I've already gotten the max and average connection duration. (So probably very self-evident that..) I also need to have some information about which connection lasted the least. I ofcourse immediately thought of the Min() function of Linq, but as you can see, the database also includes connections that started and ended instantly. Therefore, that data isn't actually "valid" for data analysis.
So my question is how to get the minimum value, but if the value = 0, get the next value that is the lowest.
My linq query so far (which implements the Min() function):
var min = from connections in Connections
join stores in Stores
on connections.Store_Ref equals stores.Id
group connections
by stores.Description into groupedStores
select new
{
Store_Description = groupedStores.Key,
Connection_Duration = groupedStores.Min(connections =>
(SqlMethods.DateDiffSecond(connections.Start, connections.End)))
};
I know that it's possible to get the valid values through multiple queries and/or statements though, but I was wondering if it's possible to do it all in just one query, since my program expects linq queries to be returned and my preference goes to keeping the program as "light" as possible.
If you have to great/simple method to do so, please share it. Your contribution is very appreciated! :)
What if you add, before the select new, a let clause for the duration of the conection with something like:
let duration = SqlMethods.DateDiffSecond(connections.Start, connections.End)
And then add a where clause
where duration != 0
var min = from connections in Connections.Where(connections => (SqlMethods.DateDiffSecond(connections.Start, connections.End) > 0)
join stores in Stores
on connections.Store_Ref equals stores.Id
group connections
by stores.Description into groupedStores
select new
{
Store_Description = groupedStores.Key,
Connection_Duration = groupedStores.Min(connections =>
(SqlMethods.DateDiffSecond(connections.Start, connections.End)))
};
Try this, With filtering the "0" values you will get the right result, at least that is my taught.
Include a where clause before calculating the Min value.
groupedStores.Where(conn => SqlMethods.DateDiffSecond(conn.Start, conn.End) > 0)
.Min(conn => (SqlMethods.DateDiffSecond(conn.Start, conn.End))

Resources