I have a Datatable containing data like:
Id | Val1 | Val2
0 | 0 | 1
1 | 3 | 0
2 | 0 | 3
3 | 2 | 1
I need to know the MAX value of the SUM of Val1+Val2 (in the example table is 3) and then extract rows having these values.
I know how I can extract rows with:
MyTable.Select("(Val1 + Val2) = 3")
But I'm not able to get the max value of the sum so to put it into the "Select"
I think you will have to loop through the table to find the maximum sum, which could be done using LINQ:
Dim maxSum = (
From r In MyTable.AsEnumerable()
Select r.Field(Of Integer)("Val1") + r.Field(Of Integer)("Val2")
).Max()
And then just use that in your select:
MyTable.Select("(Val1 + Val2) = " & maxSum)
Related
I have a table foo with columns id, number_of_foos, and parent_foo. number_of_foos is an integer and parent_foo is a reference to another row's id. Each row will have an integer in parent_foo or null if it has no parent.
id | number_of_foos | parent_foo
---+----------------+-----------
1 | 10 | null
2 | 7 | null
3 | 6 | null
4 | 13 | 1
5 | 9 | 3
6 | 1 | 4
Given an id number, I want to find the total amount of "foo"s in the "foo chain", i.e. the count of foos for that id and its parent (and its parent, and its parent...). So for example, the total amount of foos WHEN id = 6 is 1 + 13 + 10 = 24.
Okay.
BUT, I also want to subtract 1 for each parent. So WHEN id = 6 is actually (1 + 13 + 10) - 2 = 22.
Is this possible?
demo: db<>fiddle
WITH RECURSIVE rec AS (
SELECT
parent_foo,
number_of_foos
FROM foo
WHERE id = 6
UNION
SELECT
f.parent_foo,
r.number_of_foos + f.number_of_foos - 1
FROM foo f
JOIN rec r ON f.id = r.parent_foo
)
SELECT number_of_foos
FROM rec
WHERE parent_foo IS NULL;
Using a WITH RECURSIVE CTE you could run through your data structure. A recursive CTE consists of two parts:
Starting point: Selecting the first row. In your case the parent of the first value and its number_of_foos value.
The recursion part where you select the row with id == parent_foo of last recursion. In this step you can integrate the adding part as well: Just adding the new numbers_of_foo - 1 to the last one.
Finally you can give out the row without any parent which is the grandmost parent of your starting value and it contains the expected sum.
I have a table that contains more than 16,000,000 records.
Each record has a primary key (formed by five fields "tsid, plisid, plifc, plisc, dt"), and two counter fields ("icount, aicount").
There is a relation between some of the records in the table.
To simplify the problem let's say we have only these two records
tsid, plisid, plifc, plisc, dt, icount, aicount
10 1 0 0 0 2 2
11 1 0 0 0 7 0
The requirement:
I want to update the "aicount" field in the second record to be 9 (i.e. "icount" in the second record + "aicount" in the first record).
The relation between the first and second record is that they have the same values in (plisid, plifc, plisc, dt), and the tsid value of the second record == the tsid of the first record + 1
The desired result after the update is:
tsid, plisid, plifc, plisc, dt, icount, aicount
10 1 0 0 0 2 2
11 1 0 0 0 7 9
I tried this SQL statement in PostgreSQL but I got a syntax error "ERROR: syntax error at or near "SELECT" Position: 59"
UPDATE table1 SET
table1.aicount = table1.icount + SELECT COALESCE( (SELECT CASE
WHEN table1temp.aicount IS NULL
THEN 0
ELSE table1temp.aicount
END
FROM table1 table1temp
WHERE table1temp.tsid = table1.tsid - 1
AND table1temp.plisid = table1.plisid
AND table1temp.plifc = table1.plifc
AND table1temp.plisc = table1.plisc
AND table1temp.dt = table1.dt), 0)
WHERE table1.tsid = 10;
What is the wrong in the statement above? Any idea or suggestions?
The error caused because you couldn't use select subquery to add an update column.
You seem to want to get the number, which this row icount number add with last recorded aicount number
I would use LAG function to get last recorded aicount number in subquery then update the number.
There are three parameters in LAG function.
First your column, which you want to get the last column value.
offset from this column value defaults to 1
default value. default to null
lag(value any [, offset integer [, default any ]])
returns value evaluated at the row that is offset rows after the current row within the partition; if there is no such row, instead return default. Both offset and default are evaluated with respect to the current row. If omitted, offset defaults to 1 and default to null
CREATE TABLE T(
tsid int,
plisid int,
plifc int,
plisc int,
dt int,
icount int,
aicount int
);
INSERT INTO T VALUES (10,1,0,0,0,2,2);
INSERT INTO T VALUES (11,1,0,0,0,7,0);
UPDATE T
SET aicount = t1.totle
FROM
(
SELECT *,(LAG(aicount,1,0) over(order by tsid) + icount) totle
FROM T
) t1
WHERE
T.tsid = t1.tsid
AND T.plisid = t1.plisid
AND T.plifc = t1.plifc
AND T.plisc = t1.plisc
AND T.dt = t1.dt
Query 1:
SELECT * FROM T
Results:
| tsid | plisid | plifc | plisc | dt | icount | aicount |
|------|--------|-------|-------|----|--------|---------|
| 10 | 1 | 0 | 0 | 0 | 2 | 2 |
| 11 | 1 | 0 | 0 | 0 | 7 | 9 |
Try the following query-:
update T
set aicount=mm.m
from(
select sum(iCount) over (partition by plisid,plifc,plisc,dt order by tsid) m from T
) mm
SQL Server
I have a table which I have shown a simplified example of below:
ID | Item1 | Item2 | Item3 | Item4 | Item5
------------------------------------------
A | NULL | NULL | YES | YES | NULL
B | NULL | NULL | NULL | YES | NULL
C | NULL | NULL | NULL | NULL | NULL
I want to return the following data set:
ID | Count
------------
A | 2
B | 1
C | 0
I.e. I want a count of how many of the columns are NOT NULL for that ID
One potential solution would be
SELECT
ID,
SUM(
IIf(Item1 is NULL,0,1)
+
IIf(Item2 is NULL,0,1)
+
IIf(Item3 is NULL,0,1)
+
IIf(Item4 is NULL,0,1)
+
IIf(Item5 is NULL,0,1)
) 'Count'
FROM
tableName
GROUP BY
ID
However in practice the real table I am using has over a hundred columns and I would prefer to avoid having to write out the names of each column. Is there a simpler way to do this?
You can use VBA to loop through every record and field:
Function CountFields()
Set db = CurrentDb()
db.Execute ("delete * from ItemCounts")
Set RS = db.OpenRecordset("select * from [DataTable]")
RS.MoveFirst
Do While Not RS.EOF
Id = RS.Fields("ID").Value
Count = 0
For Each Item In RS.Fields
If (Item.Name <> "ID" And RS.Fields(Item.Name).Value <> "") Then Count = Count + 1
Next Item
db.Execute ("insert into ItemCounts (ID,[count]) select " & Id & "," & Count)
RS.MoveNext
Loop
MsgBox ("done")
End Function
This puts the counts in a table called ItemCounts, which needs to be set up before the VBA is executed. The fields in that table are ID and Count.
And, if you can reformat the source data, I agree with Minty - but I know that's not always feasible.
Your data is not normalised and therefore you are having to perform gymnastics in your code to work around the problem.
Your data should be stored vertically not horizontally;
ID | ItemNo | Value
---------------------
A | 2 | 1
A | 3 | 1
B | 4 | 1
This would make your query a simple total query, and allow for any number of items. You are also only storing data when you have some not for every case.
Edit: This will loop through the fields
Dim Rst As Recordset
Dim f As Field
Set Rst = CurrentDb.OpenRecordset(TableName)
For Each f In Rst.Fields
Debug.Print (f.name)
Next
Rst.Close
You can reduce it a little:
SELECT
ID,
ABS(SUM((Item1 is Not NULL)+(Item2 is Not NULL)+(Item3 is Not NULL)+(Item4 is Not NULL)+(Item5 is Not NULL))) As [Count]
FROM
tableName
GROUP BY
ID
How to sort this table in Oracle9:
START | END | VALUE
A | F | 1
D | H | 9
F | C | 8
C | D | 12
To make it look like this?:
START | END | VALUE
A | F | 1
F | C | 12
C | D | 8
D | H | 9
Goal is to start every next row with the end from the previous row.
This cannot be done with the order by clause alone, as it would have to find the record without a predecessor first, then find the next record comparing end and start column of the two records etc. This is an iterative process for which you need a recursive query.
That recursive query would find the first record, then the next and so on, giving them sequence numbers. Then you'd use the result and order by those generated numbers.
Here is how to do it in standard SQL. This is supported from Oracle 11g onwards only, however. In Oracle 9 you'll have to use CONNECT BY with which I am not familiar. Hopefully you or someone else can convert the query for you:
with chain(startkey, endkey, value, pos) as
(
select startkey, endkey, value, 1 as pos
from mytable
where not exists (select * from mytable prev where prev.endkey = mytable.startkey)
union all
select mytable.startkey, mytable.endkey, mytable.value, chain.pos + 1 as pos
from chain
join mytable on mytable.startkey = chain.endkey
)
select startkey, endkey, value
from chain
order by pos;
UPDATE: As you say the data is cyclic, you'd have to change above query so as to start with an arbitrarily chosen row and stop when through:
with chain(startkey, endkey, value, pos) as
(
select startkey, endkey, value, 1 as pos
from mytable
where rownum = 1
union all
select mytable.startkey, mytable.endkey, mytable.value, chain.pos + 1 as pos
from chain
join mytable on mytable.startkey = chain.endkey
)
cycle startkey set cycle to 1 default 0
select startkey, endkey, value
from chain
where cycle = 0
order by pos;
i've two columns in mysql db table votes : accept and reject
i want to query only the top result after the accept-reject column values
table : votes
=================
accept | reject
=================
7 | 9
5 | 1
2 | 15
5 | 1
i want just the positive and top value, here 5-1 = 4
actually, i've lot of other columns along with accept and reject..i just want to ORDER the results by the top value of difference(positive only) and LIMIT it to 1 so that i can get the one row i want..was i clear? :)
how to write query for this?
thanks..
Use:
SELECT t.accept,
t.reject,
t.accept - t.reject AS difference
FROM VOTES t
WHERE t.accept - t.reject > 0
ORDER BY difference DESC
LIMIT 1
Alternate using subquery:
SELECT v.accept,
v.reject
FROM VOTES v
WHERE v.accept - v.reject > 0
JOIN (SELECT MAX(t.accept - t.reject) AS difference
FROM VOTES t
WHERE t.accept - t.reject > 0) x ON x.difference = (v.accept - v.reject)
SELECT (accept - reject) as top_value FROM table WHERE (accept - reject) > 0
So if you have values like this:
=============================
accept | reject | top_value
=============================
5 | 1 | 4
7 | 9 | -2
2 | 15 | -13
5 | 5 | 0
the query will select only row 1.
I'm assuming those two columns are just an extract from your table, and you want the entire row where (accept-reject) is maximum. Then you can do it like this:
SELECT * FROM votes
WHERE accept-reject = (SELECT MAX(accept-reject) FROM votes)
LIMIT 1