Kotlin-Exposed : How to select a max timestamp - kotlin-exposed

New to the Jetbrains Exposed Framework here. I have an oracle table with 3 fields in it.
ID
TIMESTAMP
FLAG
1234
May1 12AM
Y
1234
May1 3PM
N
I want to query the max timestamp row where FLAG = Y, but I'm not sure how to do this.
Employee.run {
val results = select {(id eq employeeId) and (flag eq "Y")}
// If no row with Flag = Y then I guess I can just return if results are empty
!results.empty()
}
I'm not sure how to check for a max timestamp in this.

Ended up figuring out a way to do it. I'm sure there's a better way with both Kotlin and Expose.
fun Person.hasFlag(employeeId: String): Boolean {
return transaction(db) {
Employee.run {
val results = slice(id, timeStamp, flag).select {(id eq employeeId)}.groupBy(id, timeStamp, flag)
if (results.empty()) false else results.map {
Pair(it[timeStamp], it[flag])
}.maxByOrNull { m -> m.first }?.second == "Y"
}
}
}

Related

Comparing two tables using groovy script in soapui

I need to compare the values of 2 tables in SQL Server. I have created script but the script I've made is only comparing the whole table as one. The one I needed is comparing each row of 2 tables. Here is my script I've made
import groovy.sql.Sql
import java.sql.ResultSet
import com.eviware.soapui.support.GroovyUtils
import groovy.sql.DataSet
def sql = Sql.newInstance("jdbc:sqlserver://MSSQLSERVER01:1433",
"User", "password", "com.microsoft.sqlserver.jdbc.SQLServerDriver")
resultsA = sql.eachRow("SELECT * FROM Bikestores.production.brands"){
temp1=it.toRowResult().values().join(", ")
}
resultsB = sql.eachRow("SELECT * FROM Bikestores.dbo.sample"){
temp2=it.toRowResult().values().join(", ")
}
while(temp1 != null && temp2 != null){
brandA = temp1
brandB = temp2
if(brandA==brandB){
log.info "True"
break
}
else{
log.info "False"
break
}
}
sql.close()
The result of this is False since there is a difference in values.
I need to compare each row, like I will get 9 results since I have a 9 rows. If you have better scripts please let me know. Thank you.
Edit:
Sample data
Table 1
id|name | check
1 | abc | yes
2 | def | yes
3 | ghi | yes
4 | jkl | yes
Table 2
id|name | check
1 | abc | yes
2 | def | yes
3 | pqr | yes
4 | mno | yes
Expected Result
[table1_name][table2_name]: true
[table1_name][table2_name]: true
[table1_name][table2_name]: false
[table1_name][table2_name]: false
Somewhat straight-forward way:
...
List<String> tableA = sql.rows("SELECT * FROM Bikestores.production.brands")*.join(',')
sql.rows("SELECT brand_id FROM Bikestores.dbo.sample")*.join(',').each{
log.info "$it equals -> ${tableA.contains( it )}"
}
My Thoughts :
- The right and suggestible way is filtering by sql query itself like select * from table1,table2 where field_1 == field_2. u don't need outside computation.
Or If u really want to do it by code. please try to share the sample table data and expected output format. then only we can help u.
Answer:
ur code not collecting the results, it just replaces the latest line of eachRow(). This is the modified code :
temp1 = []
temp2 = []
resultsA = sql.eachRow("SELECT id FROM Bikestores.production.brands"){
temp1.append(it[0])
}
resultsB = sql.eachRow("SELECT brand_id FROM Bikestores.dbo.sample"){
temp2.append(it[0]) // If u having one column why u getting values list
}
temp1.each{ brandA ->
temp2.each{ brandB ->
if(brandA==brandB){
log.info "$brandA : $brandB : True"
}
else{
log.info "$brandA : $brandB : False"
}
}
sql.close()
Note :
It seems the first query select * from not correct. It will provide all column values. (r u aware of this ?)
I don't know why u r joining all values on a row using .values().join(", ") when u r going to compare with brand_id. If i guess right brands table should have a column as id (intuitive).
I think u r not sure what u r getting. I hope this notes will clarify and encourage u to ask better question.
Update 1:
After seeing ur sample, i guess this is what u r expecting....
def getResult(query, sql) // method changed
{
temp = []
sql.eachRow(query){
temp.add(it.toRowResult()) // changed
}
temp
}
resultsA = getResult("SELECT id, name, check FROM Bikestores.production.brands", sql)
resultsB = getResult("SELECT id, name, check FROM Bikestores.dbo.sample", sql)
resultsA.each{ brandA ->
resultsB.each{ brandB ->
if (brandA.id.trim() == brandB.id.trim()) // condition only for id match
log.info "[${brandA.name}][${brandB.name}] : ${brandA.name == brandB.name}"
}
sql.close()

Linq query count

select count(tblVV.VNme) as total,
tblvV.VNme
from tblVV
inner join tblRV
on tblVV.MID=tblRV.ID
inner join tblRe
on tblRV.RID=tblRe.RID
where tblRe.StartDate>= '2016-07-01 00:00:00' and
tblRe.EndDate<= '2016-07-31 23:59:59' and
tblRe.Reg= 'uk' and
tblRV.RegNo='BR72' and
tblVV.VNme <>''
group by tblVV.VNme
For the above query I get:
total Vame
1 DDSB
11 MV
The above SQL query shows me correct data so now i try to convert above query to linq query
[WebMethod]
public static string GetVo(string RegNo)
{
string data = "[";
try
{
Ts1 DB = new Ts1();
var re = (from vehvoila in DB.tblVV
join regveh in DB.tblRV on vehvoila.MID equals regveh.ID
join reg in DB.tblReg on regveh.RID equals reg.RID
where regveh.RegNo == RegNo &&
vehvoila.Vame != ""
group vehvoila by vehvoila.Vame into g
select new
{
VNme = g.Key,
cnt = g.Select(t => t.Vame).Count()
}).ToList();
if (re.Any())
{
data += re.ToList().Select(x => "['" + x.Vame + "'," + x.cnt + "]")
.Aggregate((a, b) => a + "," + b);
}
data += "]";
}
linq query show me return data like this
[['DDSB',1],['DPSB',1],['DSB',109],['MV',39],['PSB',1]]
Whereas I want data this
[['DDSB',1],['MV',11]]
Now the data which return SQL query is correct so how I correct linq query
Note: forget fromdate,todate,region parameter in SQL query . because I have page in which I put dropdown and fromdate and todate picker and there is button so when I select values i.e. UK, and dates then data is display in table then when I click on any row in table then I want to get this data in data +=”]”;
actually above linq query work behind clicking on row
total Vame
1 DDSB
11 MV
You can write it all like this:
Ts1 db = new Ts1();
var result = (from vehvoila in db.tblVV
join regveh in db.tblRV on vehvoila.MID equals regveh.ID
join reg in db.tblReg on regveh.RID equals reg.RID
where reg.StartDate >= new DateTime(2016, 7, 1) &&
reg.EndDate < new DateTime(2016, 8, 1) &&
reg.Reg == "uk" &&
regveh == "BR72" &&
vehvoila != ""
group vehvoila by vehvoila.Vame into g
select $"[{g.Key},{g.Count()}]");
var data = $"[{string.Join(",", result)}]";
Because you only use the result for the creation of the string in the select I just return the string formatted for a single item and then later used string.Join instead of using the .Aggregate - I think a bit cleaner
The $"{}" syntax is the C# 6.0 string interpolation
In the condition of the EndDate I decided to use < instead of the <= with the change of the date - At least in oracle when you partition the table by date it is better for performance - maybe also in sql server
Without string interpolation:
Ts1 db = new Ts1();
var result = (from vehvoila in db.tblVV
join regveh in db.tblRV on vehvoila.MID equals regveh.ID
join reg in db.tblReg on regveh.RID equals reg.RID
where reg.StartDate >= new DateTime(2016, 7, 1) &&
reg.EndDate < new DateTime(2016, 8, 1) &&
reg.Reg == "uk" &&
regveh == "BR72" &&
vehvoila != ""
group vehvoila by vehvoila.Vame into g
select new { Key = g.Key, Count = g.Count()})
.AsEnumerable()
.Select(g => string.Format("[{0},{1}]",g.Key, g.Count));
var data = string.Format("[{0}]",string.Join(",", result));

SQL CLR Aggregate incorrectly returning null

I've added a user defined aggregate to my database for computing the product of a group.
The code was taken essentially verbatim from here.
I'm using the function to calculate the lifetime to date returns of financial instruments for which I have monthly return data. The table looks something like this:
----------------------------------------------------------
| InstrumentId(int) | MonthEnd(datetime) | Return(float) |
----------------------------------------------------------
My query looks like this:
SELECT R1.InstrumentId,
R1.MonthEnd,
R1.MonthlyReturn,
dbo.Product(1 + R2.MonthlyReturn) AS TotalReturn
FROM Returns R1
INNER JOIN Returns R2 ON R2.InstrumentId = R1.InstrumentId
AND R2.MonthEnd <= R1.MonthEnd
WHERE R1.InstrumentId BETWEEN 1 AND 50
GROUP BY R1.InstrumentId, R1.MonthEnd, R1.MonthlyReturn
ORDER BY R1.InstrumentId, R1.MonthEnd
The query works fine when I have only a few instruments, but adding certain instruments causes every result to be NULL. When I execute the query with OPTION(MAXDOP 1) the results are fine.
Does anyone know what's causing the issue?
EDIT:
Forgot to mention that I'm running SQL Server 2012 and the aggregate targets .NET 4.5
These are the modifications I would make to the Product aggregate if I wanted it to ignore NULLs.
Change the attribute:
[Microsoft.SqlServer.Server.SqlUserDefinedAggregate(
Microsoft.SqlServer.Server.Format.Native,
IsInvariantToDuplicates = false,
IsInvariantToNulls = true, // receiving a NULL value will be ignored
IsInvariantToOrder = true,
IsNullIfEmpty = true,
Name = "Product"
)]
Change Accumulate:
public void Accumulate(System.Data.SqlTypes.SqlDouble number) {
if (!this.HasValue && !number.IsNull) { //Don't know if we'll be passed a NULL, but protect ourselves nonetheless
this.Result = number;
} else if (number.IsNull) {
return; //Avoid setting HasValue
} else {
this.Result = System.Data.SqlTypes.SqlDouble.Multiply(this.Result, number);
}
this.HasValue = true;
}
Change Merge:
public void Merge(Product group) {
if (group.HasValue) {
if(this.HasValue) {
this.Result = System.Data.SqlTypes.SqlDouble.Multiply
(this.Result, group.Result);
} else { //We may never have had our own value set
this.Result = group.Result;
this.HasValue = true;
}
}
}
I'm not sure if the change to Merge is truly needed, but I'd do it for safety's sake.
If 1 + R2.MonthlyReturn is positive, I would considered use of exp(sum(log(...))) equivalent:
SELECT R1.InstrumentId,
R1.MonthEnd,
R1.MonthlyReturn,
EXP(SUM(LOG(1 + R2.MonthlyReturn))) AS TotalReturn
FROM Returns R1
INNER JOIN Returns R2 ON R2.InstrumentId = R1.InstrumentId
AND R2.MonthEnd <= R1.MonthEnd
WHERE R1.InstrumentId BETWEEN 1 AND 50
GROUP BY R1.InstrumentId, R1.MonthEnd, R1.MonthlyReturn
ORDER BY R1.InstrumentId, R1.MonthEnd

Convert SQL Server varbinary(max) into a set of primary keys of type int

Disclaimer: not my code, not my database design!
I have a column of censusblocks(varbinary(max), null) in a MS SQL Server 2008 db table (call it foo for simplicity).
This column is actually a null or 1 to n long list of int. The ints are actually foreign keys to another table (call it censusblock with a pk id of type of int), numbering from 1 to ~9600000.
I want to query to extract the censusblocks list from foo, and use the extracted list of int from each row to look up the corresponding censusblock row. There's a long, boring rest of the query that will be used from there, but it needs to start with the census blocks pulled from the foo table's censusblocks column.
This conversion-and-look-up is currently handled on the middle tier, with a small .NET utility class to convert from List<int> to byte[] (and vice versa), which is then written into/read from the db as varbinary. I would like to do the same thing, purely in SQL.
The desired query would go something along the lines of
SELECT f.id, c.id
FROM foo f
LEFT OUTER JOIN censusblock c ON
c.id IN f.censusblocks --this is where the magic happens
where f.id in (1,2)
Which would result in:
f.id | c.id
1 8437314
1 8438819
1 8439744
1 8441795
1 8442741
1 8444984
1 8445568
1 8445641
1 8447953
2 5860657
2 5866881
2 5866881
2 5866858
2 5862557
2 5870475
2 5868983
2 5865207
2 5863465
2 5867301
2 5864057
2 5862256
NB: the 7-digit results are coincidental. The range is, as stated above, 1-7 digits.
The actual censusblocks column looks like
SELECT TOP 2 censusblocks FROM foo
which results in
censublocks
0x80BE4280C42380C7C080CFC380D37580DC3880DE8080DEC980E7D1
0x596D3159858159856A59749D59938B598DB7597EF7597829598725597A79597370
For further clarification, here's the guts of the .NET utility classes conversion methods:
public static List<int> getIntegersFromBytes(byte[] data)
{
List<int> values = new List<int>();
if (data != null && data.Length > 2)
{
long ids = data.Length / 3;
byte[] oneId = new byte[4];
oneId[0] = 0;
for (long i = 0; i < ids; i++)
{
oneId[0] = 0;
Array.Copy(data, i * 3, oneId, 1, 3);
if (BitConverter.IsLittleEndian)
{ Array.Reverse(oneId); }
values.Add(BitConverter.ToInt32(oneId, 0));
}}
return values;
}
public static byte[] getBytesFromIntegers(List<int> values)
{
byte[] data = null;
if (values != null && values.Count > 0)
{
data = new byte[values.Count * 3];
int count = 0;
byte[] idBytes = null;
foreach (int id in values)
{
idBytes = BitConverter.GetBytes(id);
if (BitConverter.IsLittleEndian)
{ Array.Reverse(idBytes); }
Array.Copy(idBytes, 1, data, count * 3, 3);
count++;
} }
return data;
}
An example of how this might be done. It is unlikely to scale brilliantly.
If you have a numbers table in your database it should be used in place of nums_cte.
This works by converting the binary value to a literal hex string, then reading it in 8-character chunks
-- create test data
DECLARE #foo TABLE
(id int ,
censusblocks varbinary(max)
)
DECLARE #censusblock TABLE
(id int)
INSERT #censusblock (id)
VALUES(1),(2),(1003),(5030),(5031),(2),(6)
INSERT #foo (id,censusblocks)
VALUES (1,0x0000000100000002000003EB),
(2,0x000013A6000013A7)
--query
DECLARE #biMaxLen bigint
SELECT #biMaxLen = MAX(LEN(CONVERT(varchar(max),censusblocks,2))) FROM #foo
;with nums_cte
AS
(
SELECT TOP (#biMaxLen) ((ROW_NUMBER() OVER (ORDER BY a.type) - 1) * 8) AS n
FROM master..spt_values as a
CROSS JOIN master..spt_values as b
)
,binCTE
AS
(
SELECT d.id, CAST(CONVERT(binary(4),SUBSTRING(s,n + 1,8),2) AS int) as cblock
FROM (SELECT Id, CONVERT(varchar(max),censusblocks,2) AS s FROM #foo) AS d
JOIN nums_cte
ON n < LEN(d.s)
)
SELECT *
FROM binCTE as b
LEFT
JOIN #censusblock c
ON c.id = b.cblock
ORDER BY b.id, b.cblock
You could also consider adding your existing .Net conversion methods into the database as an assembly and accessing them through CLR functions.
This is off-topic, but I couldn't resist writing these conversions so they use IEnumerables instead of arrays and Lists. This might not be faster per se, but is more general and would allow you to perform the conversion without loading the whole array at once, which may be helpful if the arrays you are dealing with are large.
Here it is, for what it's worth:
static IEnumerable<int> BytesToInts(IEnumerable<byte> bytes) {
var buff = new byte[4];
using (var en = bytes.GetEnumerator()) {
while (en.MoveNext()) {
buff[0] = en.Current;
if (en.MoveNext()) {
buff[1] = en.Current;
if (en.MoveNext()) {
buff[2] = en.Current;
if (en.MoveNext()) {
buff[3] = en.Current;
if (BitConverter.IsLittleEndian)
Array.Reverse(buff);
yield return BitConverter.ToInt32(buff, 0);
continue;
}
}
}
throw new ArgumentException("Wrong number of bytes.", "bytes");
}
}
}
static IEnumerable<byte> IntsToBytes(IEnumerable<int> ints) {
if (BitConverter.IsLittleEndian)
return ints.SelectMany(
b => {
var buff = BitConverter.GetBytes(b);
Array.Reverse(buff);
return buff;
}
);
return ints.SelectMany(BitConverter.GetBytes);
}
Your code seems to like encoding an int into 3 bytes instead of 4, which would cause problems with values that don't fit into 3 bytes (including negatives) - is that intentional?
BTW, you should be able to adapt this (or your) code for execution in SQL Server CLR. This is not exactly "in SQL", but is "in DBMS".
you can use Convert(int, censusBlock) to convert the varchar value to int value.
the you can join on that column.
Or have i misunderstood the question?

setSelection on Spinner based on rowId

I have a Spinner View that's populated through a SimpleCursorAdapter.
Based on the selection I need to save the rowid in the entry database (position won't work because things can be added and deleted from the Spinner Database).
This I can do by using spinner.getAdapter().getItemId(pos);. But When I edit an entry I need to make the Spinner position selected that is associated with this rowid (currently).
spinner.setSelection(position); won't work because I have the rowid, I need a way to find the current position of the item in the current spinner based on the rowid in the database.
If you want to set the selection of a Spinner thats backed by a CursorAdapter, you can loop through all the items in the Cursor and look for the one you want (assuming that the primary key in your table is named "_id"):
Spinner spinner = (Spinner) findViewById(R.id.spinner);
spinner.setAdapter(new SimpleCursorAdapter(...));
for (int i = 0; i < spinner.getCount(); i++) {
Cursor value = (Cursor) spinner.getItemAtPosition(i);
long id = value.getLong(value.getColumnIndex("_id"));
if (id == rowid) {
spinner.setSelection(i);
}
}
If you want to get the rowid of a selected item, you can do something similar:
Cursor cursor = (Cursor) spinner.getSelectedItem();
long rowid = cursor.getLong(cursor.getColumnIndex("_id"));
There might be a quicker way to do it, but that's always worked for me.
Had an idea when writing this, made a hashtable with rowid->pos when populating the spinner and then used that. Might help someone if they're searching.
I agree with Erich Douglass's above answer but i found fastest loop syntax which will be useful while spinner.getCount() is greater than 50k to 100k.
/* 1 (fastest) */
for (int i = initializer; i >= 0; i--) { ... }
/* 2 */
int limit = calculateLoopLimit();
for (int i = 0; i < limit; i++) { ... }
/* 3 */
Type[] array = getMyArray();
for (Type obj : array) { ... }
/* 4 */
for (int i = 0; i < array.length; i++) { ... }
/* 5 */
for (int i = 0; i < this.var; i++) { ... }
/* 6 */
for (int i = 0; i < obj.size(); i++) { ... }
/* 7 (slowest) */
Iterable<Type> list = getMyList();
for (Type obj : list) { ... }
So i think we can use here second for better performance:
int spinnerCount = spinner.getCount();
for (int i = 0; i < spinnerCount; i++) {
Cursor value = (Cursor) spinner.getItemAtPosition(i);
long id = value.getLong(value.getColumnIndex("_id"));
if (id == rowid) {
spinner.setSelection(i);
}
}
I think that instead of a for loop is better a while, because when you find your item, can break the loop.
int spinnerCount = spinner.getCount();
int i = 0;
while(i++ < spinnerCount) {
Cursor value = (Cursor) spinner.getItemAtPosition(i);
long id = value.getLong(value.getColumnIndex("_id"));
if (id == rowid) {
spinner.setSelection(i);
break;
}
}
First step, create view for your data set, with joins etc.:
CREATE VIEW my_view AS
SELECT _id, field FROM my_table
Second step:
CREATE VIEW my_view2 AS
SELECT count(*) AS row_id, q1.*
FROM my_view AS q1
LEFT JOIN my_view AS q2
WHERE q1._id >= q2._id
GROUP BY q1._id
Then simply:
SELECT * FROM my_view2
Results:
row_id | _id | field
1 4 XbMCmUBFwb
2 6 Te JMejSaK
3 8 dDGMMiuRuh
4 10 phALAbnq c
5 11 EQQwPKksIj
6 12 PAt tbDnf
7 13 f zUSuhvM
8 14 TIMBgAGhkT
9 15 OOcnjKLLER
To get position by id:
SELECT * FROM my_view2 WHERE _id=11
Results:
row_id | _id | field
5 11 EQQwPKksIj
Hope that help
https://stackoverflow.com/a/5040748/1206052
dziobas
has provided an awesome answer.. But I am not surprised why nobody has recommended it.. just want to make some correction in his answer..
CREATE VIEW my_view2 AS
SELECT count(*) AS row_id, q1.*
FROM my_view AS q1
LEFT JOIN my_view AS q2
ON (q1._id >= q2._id)
GROUP BY q1._id
I just replaced "where" with "on" that is required by join..
now u have all the items with their Positions associated with there ID's..
Just assign the ROW_id to the setselection() of spinner
Why do it the hard way when you can do it the right way?
I refer to the manual:
http://d.android.com/reference/android/widget/AdapterView.OnItemSelectedListener.html#onItemSelected%28android.widget.AdapterView%3C?%3E,%20android.view.View,%20int,%20long%29
example code:
spinner.setOnItemSelectedListener(new OnItemSelectedListener() {
public void onItemSelected(AdapterView<?> parent, View view, int position, long id)
{
int index = spinner.getSelectedItemPosition();
Toast.makeText(getBaseContext(),
"You have selected item : " + index + " which is row " + id,
Toast.LENGTH_SHORT).show();
}
public void onNothingSelected(AdapterView<?> arg0) {}
});
Thanks to evancharlton on #android-dev for this enlightment. :)

Resources