Countif statement in Postgresql - sql

How can I use countif statement in PostgreSQL?
max(COUNTIF(t1.A1:C10,t2.a1),COUNTIF(t1.A1:C10,t2.b1),COUNTIF(t1.A1:C10,t2.c1))
I have table1 which is more then a million rows
a
b
c
M5
16
27
31
3
7
27
and table2 more then 100 rows including different dates after column c
a
b
c
10
15
16
30
40
50
60
70
80
16
18
37
5
12
16
8
31
28
11
12
13
7
9
31
2
7
21
20
16
27
8
12
17
2
8
14
3
14
15
The outcome should be something like this
a
b
c
M5
16
27
31
3
3
7
27
2
Tried the below query but the outcome is not correct
UPDATE table1 SET m5 = greatest(
case When a in(select unnest(array[a,b,c]) from (select * from table2 order by date DESC limit 10) foo) then 1 else 0 END,
case When b in(select unnest(array[a,b,c]) from (select * from table2 order by date DESC limit 10) foo) then 1 else 0 END,
case When c in(select unnest(array[a,b,c]) from (select * from table2 order by date DESC limit 10) foo) then 1 else 0 END)

Assuming your columns are fixed and predictable, I think you could put all possible table values into a single column and then do counts for each occurrence:
with exploded as (
select a from table2
union all
select b from table2
union all
select c from table2
)
select a, count (*) as count
from exploded e
group by a
So for example, the value 7 occurs twice (which would be reflected in this output).
From there, you can just do the updates from the CTE:
with exploded as (
select a from table2
union all
select b from table2
union all
select c from table2
),
counted as (
select a, count (*) as count
from exploded e
group by a
)
update table1 t
set m5 = greatest (ca.count, cb.count, cc.count)
from
counted ca,
counted cb,
counted cc
where
t.a = ca.a and
t.b = cb.a and
t.c = cc.a
The only issue I see is if one of the values does not come up (the inner join fails), but in your example that doesn't seem to happen.
If it is possible, I would think that could be resolved with one more CTE to fill in missing values from table1 in the set of possible occurrences.

Related

SQL: How to join two columns in a specific way?

I am working with an Oracle Database and I am new to SQL in general.
I have a table with data and month columns. After filtering the data I have just a few rows left. But I want to get two columns: 1-st column with 12 months listed (1,2,3,4,5,6,7,8,9,10,11,12) and second column with values from original data (if exist) or zeroes.
F.e.: Original data:
MONTH VALUE
9 96
What I want:
MONTH VALUE
1 0
2 0
3 0
4 0
5 0
6 0
7 0
8 0
9 96
10 0
11 0
12 0
I have already tried to use join and union all functions but it didn't work out.
First generate a sequence of 12 months number then use left join
select monthNo, coalesce(Value,0) as value from
(
SELECT 1 MonthNo
FROM dual
CONNECT BY LEVEL <= 12
)A left join originaltable b on A.monthNo=b.month
is this what are you looking for?
WITH tab AS(SELECT LEVEL AS m , null as value FROM DUAL CONNECT BY LEVEL <= 12)
, tab2 AS(SELECT 9 as m, 96 as VALUE FROM DUAL)
select t1.m
,coalesce(t2.value,0) as value
from tab t1
left join tab2 t2 on t1.m = t2.m
order by 1
Bro enjoy...
select months.month ,original_data.VALUE
from original_data
Right JOIN (VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12)) months(month) on
months.month = original_data.MONTH
order by months.month --optional

Sum Amount, display full resultset where Groups of Column Values Match in Same Table Oracle SQL

I need to get the sum of all TOTAL fields where the ID, RECNO and DRCR fields have the same value, while also displaying these fields in the result set.
eg
ID RECNO SECRECNO DRCR TOTAL
1 9 5 D 25
1 9 12 D 22
1 9 6 C 33
1 9 5 D 50
1 8 2 D 12
1 8 2 C 23
2 9 5 D 100
So the results of the query should be
ID RECNO SECRECNO DRCR SUM(TOTAL)
1 9 5 D 75
1 9 12 D 22
1 9 6 C 33
1 8 2 D 12
1 8 2 C 23
2 9 5 D 100
This query will give the results set, without the TOTAL:
select distinct t1.recno, t1.secrecno
from table t1, table t2
where t1.recno = t2.recno and t.id = '1' and t1.drcr = 'D'
But I can't see how to SUM the TOTAL of these results.
How to do this?
select t1.id,
t1.recno,
t1.secrecno,
t1.drcr,
SUM( TOTAL )
from table t1
INNER JOIN
table t2
ON ( t1.recno = t2.recno )
WHERE t1.id = '1'
AND t1.drcr = 'D'
GROUP BY
t1.id,
t1.recno,
t1.secrecno,
t1.drcr

SQL group numbers that are 'close' together using a threshold value

Consider the table:
id value
1 2
2 4
3 6
4 9
5 10
6 12
7 19
8 20
9 22
I want to group them by a threshold value so that I can find values that are 'close' together.
To do this I want another column that groups these numbers together. For this example use 2 as the
threshold. The result should be like this. It does not matter what is used as the group label, just
as long as it makes it easy to query later.
id value group_label
1 2 A
2 4 A
3 6 A
4 9 B
5 10 B
6 12 B
7 19 C
8 20 C
9 22 C
I couldn't get the version using lag() to work but here's a mysql query using variables
select id, value,
(case
when (value - #value) > 2
then #groupLabel := #groupLabel + 1
else #groupLabel
end) groupLabel, #value := value
from data cross join (
select #value := -1, #groupLabel := 0
) t1
order by value
SQLFiddle
Update
Here's a query using lag
select t1.id, t1.value, count(t2.id)
from data t1 left join (
select id, value,
case when
(value - lag(value) over (order by value)) > 2
then 1 else 0
end groupLabel
from data
) t2 on t2.groupLabel = 1
and t2.id <= t1.id
group by t1.id, t1.value
order by t1.value
SQLFiddle

access query to filter and combine count

i have two access tables
tableA
num count
1 7
2 8
3 9
4 9
5 13
6 6
tableB
num count
0 1
1 14
2 12
3 5
4 5
5 11
6 5
how can i create an access query that will ignore the numbers which have count less than 6 in any of the two tables. i.e. 0,3,4 & 6 and create a table with the rest of the numbers sorted by combined count
tableC
num count
5 24
1 21
2 20
any help appreciated
Maybe....
SELECT a.num, a.count + b.count
FROM tableA a
JOIN tableB b on b.num = a.num
WHERE a.count >= 6
AND b.count >= 6
this will include numbers which are in both A and B. To include numbers with count >= 6 that are in one table and not the other you'll have to add a Join and a "isnull" for the a.count and b.count values. ie; isnull(a.count,0) + isnull(b.count,0)
You can try something like this
SELECT DISTINCT tableA.num, [tableA].[val]+[tableB].[val] AS Expr1
FROM tableA INNER JOIN tableB ON tableA.num = tableB.num
WHERE (((tableA.val)>=6) AND ((tableB.val)>=6));
How about
SELECT x.Num, x.Count FROM (
SELECT Num, Count(*)
FROM tableA
GROUP BY Num
HAVING Count(*)>6
UNION ALL
SELECT Num, Count(*)
FROM tableB
GROUP BY Num
HAVING Count(*)>6) x
Or if count is a field, rather than a calculation:
SELECT x.Num, x.Count FROM (
SELECT Num, Count
FROM tableA
WHERE Count>6
UNION ALL
SELECT Num, Count
FROM tableB
WHERE Count>6) x

Finding top n for each unique row

I'm trying to get the top N records for each unique row of data in a table (I'm grouping on columns b,c and d, column a is the unique identifier and column e is the score of which i want the top 1 in this case).
a b c d e
2 38 NULL NULL 141
1 38 NULL NULL 10
1 38 1 NULL 10
2 38 1 NULL 1
1 38 1 8 10
2 38 1 8 1
2 38 16 NULL 140
2 38 16 12 140
e.g. from this data i would like to find the following rows:
a b c d e
2 38 NULL NULL 141
1 38 1 NULL 10
1 38 1 8 10
2 38 16 NULL 140
2 38 16 12 140
can someone please point me in the right direction to solve this?
Your example doesn't show, and you don't explain how you determine which row is the "top" one, so I've put ?????? in the query where you need to provide a ranking column, such as
a desc
for example. In any case, this is exactly what the analytic functions in SQL Server 2005 and later are for.
declare #howmany int = 3;
with TRanked (a,b,c,d,e,rk) as (
select
a,b,c,d,e,
rank() over (
partition by b,c,d
order by ???????
)
from T
)
select a,b,c,d,e
from TRanked
where rk <= #howmany;
The nulls are a pain, but something like this:
select * from table1 t1
where a in (
select top 1 a from table1 t2
where (t1.b = t2.b or (t1.b is null and t2.b is null))
and (t1.c = t2.c or (t1.c is null and t2.c is null))
and (t1.d = t2.d or (t1.d is null and t2.d is null))
order by e desc
)
or better yet:
select * from (
select *, seqno = row_number() over (partition by b, c, d order by e desc)
from table1
) a
where seqno = 1
I believe this will do what you said (extending the idea from here):
select b,c,d,e,
rank() over
(partition by b,c,d order by e desc) "rank"
from t1 where rank < 5
Cheers.