How to get most common and least common value using sql? - sql

Input table:
a b c
1 2 1
1 2 1
1 2 2
1 3 1
1 3 3
1 3 3
2 2 5
2 2 5
2 2 7
2 3 5
2 3 8
2 3 8
Expected output:
a b min max
1 2 2 1
1 3 1 3
2 2 7 5
2 3 5 8
Logic: Group by col a and col b, get the least common and most common values from col c.
In above example for a = 1 and b = 2, the least common value for col c is 2 and most common values for col c is 1, this is depicted in the first row of the output.
Currently i am able to count the occurence of each value by using the query
select a, b, c, count(c) from table group by a, b, c

Very late answer, but I find it interesting (and fun).
You have not tagged any specific rdbms but since most databases can use CTEs:
with
counters as (
select
a, b, c, count(*) counter
from tablename
group by a, b, c
),
minmax as (
select
a, b, min(counter) mincounter, max(counter) maxcounter
from counters
group by a, b
)
select
c.a, c.b,
max(case c.counter when m.mincounter then c.c end) min,
max(case c.counter when m.maxcounter then c.c end) max
from counters c inner join minmax m
on m.a = c.a and m.b = c.b and c.counter in (m.mincounter, m.maxcounter)
group by c.a, c.b
See the demo.
Results:
| a | b | min | max |
| --- | --- | --- | --- |
| 1 | 2 | 2 | 1 |
| 1 | 3 | 1 | 3 |
| 2 | 2 | 7 | 5 |
| 2 | 3 | 5 | 8 |

Related

generate serial number in decreasing order given a variable in netezza aginity sql

Is there any SQL syntax using netezza SQL, given column number, trying to generate rows for number in decreasing order down to 0.
Below is an example of what I'm trying to do
BEFORE
ID
NUMBER
A
4
B
5
AFTER
ID
NUMBER
A
4
A
3
A
2
A
1
B
5
B
4
B
3
B
2
B
1
please also click to see screenshot for example thanks
You can use the _v_vector_idx table for this purpose
select
id, idx
from
test join _v_vector_idx
on idx <= number
order
by id asc, idx desc ;
Here's the example in action
select * from test
ID | NUMBER
-------+--------
A | 4
B | 5
(2 rows)
select id, idx from test join _v_vector_idx on
idx <= number order by id asc, idx desc ;
ID | IDX
-------+-----
A | 4
A | 3
A | 2
A | 1
A | 0
B | 5
B | 4
B | 3
B | 2
B | 1
B | 0
(11 rows)
insert into test values ('C', 3);
INSERT 0 1
select * from test;
ID | NUMBER
-------+--------
A | 4
B | 5
C | 3
(3 rows)
select id, idx from test join _v_vector_idx
on idx <= number order by id asc, idx desc ;
ID | IDX
-------+-----
A | 4
A | 3
A | 2
A | 1
A | 0
B | 5
B | 4
B | 3
B | 2
B | 1
B | 0
C | 3
C | 2
C | 1
C | 0
(15 rows)

Extract all rows of a column based on the value of another column (SQL query)

I have table
a | b
-----
1 | 3
3 | 2
3 | 4
2 | 5
3 | 6
2 | 7
how to write sql query if a = 1 then result 3 2 4 5 6 7, if a = 3 then 2 4 5 6 7, if 2 then 5 7
here is my query
select *
from table
where a in (select b from table where a = 1) or a = 1
but the result only 3 2 4 6 because 3 has 2 in col b so i want also to have 5 7
thanks
I suspect that you have a hierarchical structure, where a is the parent and b is the child, and that you are looking for all descendents of a given node.
One common way to walk such structure is a hierarchical query. In SQL Server:
with cte as (
select a, b from mytable where a = #your_parameter
union all
select t.a, t.b from mytable t inner join cte c on t.a = c.b
)
select * from cte
Demo on DB Fiddle - when given 3 as parameter:
a | b
-: | -:
3 | 2
3 | 4
3 | 6
2 | 5
2 | 7

Adding a row number respecting the order of each row

I have a table like this
id, period, tag
1 1 A
1 2 A
1 3 B
1 4 A
1 5 A
1 6 A
2 1 A
2 2 B
2 3 B
2 4 B
2 5 B
2 6 A
I would like to add a new column with a ranking, respecting the order of the row given my column 'period' to obtain something like this
id, period, tag rank
1 1 A 1
1 2 A 1
1 3 B 2
1 4 A 3
1 5 A 3
1 6 A 3
2 1 A 1
2 2 B 2
2 3 B 2
2 4 B 2
2 5 B 2
2 6 A 3
What can I do?
I try rank and dense_rank function without any success
And another candidate for CONDITIONAL_CHANGE_EVENT()
less code, and quite effective, too ...!
WITH
input(id,period,tag) AS (
SELECT 1,1,'A'
UNION ALL SELECT 1,2,'A'
UNION ALL SELECT 1,3,'B'
UNION ALL SELECT 1,4,'A'
UNION ALL SELECT 1,5,'A'
UNION ALL SELECT 1,6,'A'
UNION ALL SELECT 2,1,'A'
UNION ALL SELECT 2,2,'B'
UNION ALL SELECT 2,3,'B'
UNION ALL SELECT 2,4,'B'
UNION ALL SELECT 2,5,'B'
UNION ALL SELECT 2,6,'A'
)
SELECT
*
, CONDITIONAL_CHANGE_EVENT(tag) OVER(PARTITION BY id ORDER BY period) + 1 AS rank
FROM input;
-- out id | period | tag | rank
-- out ----+--------+-----+------
-- out 1 | 1 | A | 1
-- out 1 | 2 | A | 1
-- out 1 | 3 | B | 2
-- out 1 | 4 | A | 3
-- out 1 | 5 | A | 3
-- out 1 | 6 | A | 3
-- out 2 | 1 | A | 1
-- out 2 | 2 | B | 2
-- out 2 | 3 | B | 2
-- out 2 | 4 | B | 2
-- out 2 | 5 | B | 2
-- out 2 | 6 | A | 3
-- out (12 rows)
-- out
-- out Time: First fetch (12 rows): 14.823 ms. All rows formatted: 14.874 ms
One method is a cumulative sum based on a lag():
select t.*,
sum(case when prev_tag = tag then 0 else 1 end) over (partition by id order by period) as rank
from (select t.*, lag(tag) over (partition by id order by period) as prev_tag
from t
) t;

SQL Server UNION and offset primary key

I would like to union two tables, and in the results, have a column of the second table be offset by the max value of that column in the first table.
Example: suppose I have two tables where both have the same columns:
TableA
a | b | c
1 | 1 | 1
2 | 2 | 2
TableB
a | b | c
1 | 6 | 6
2 | 7 | 7
I want to be able to perform something like a UNION ALL which results in:
Results
a | b | c
1 | 1 | 1
2 | 2 | 2
3 | 6 | 6
4 | 7 | 7
By performing an actual UNION ALL my results are:
Results
a | b | c
1 | 1 | 1
2 | 2 | 2
1 | 6 | 6
2 | 7 | 7
UPDATE: I would also like to put this into a VIEW, which is complicating it for me.
Thanks in advance
You can get the max a value from table A and add it to column a from table B.
select a,b,c from tblA
union all
select a+t.max_a,b,c from tblB
cross join (select max(a) as max_a from tblA) t
does it value of column [a] for both table needs to follow original value ?
select a = row_number() over (order by a), b, c
from
(
select a, b, c from tableA
union all
select a, b, c from tableB
) d
alternatively, use row_number() to generate a sequence for tableb
select a = coalesce(a, max(a) over() + row_number() over(order by a)),
b, c
from
(
select a, b, c
from tableA
union all
select a = NULL, b, c
from tableB
) d
order by a

Select non distinct rows from two columns

My question is very similar to Multiple NOT distinct only it deals with multiple columns instead of one. I have a table like so:
A B C
1 1 0
1 2 1
2 1 2
2 1 3
2 2 4
2 3 5
2 3 6
3 1 7
3 3 8
3 1 9
And the result should be:
A B C
2 1 2
2 1 3
2 3 5
2 3 6
3 1 7
3 1 9
Essentially, like the above question, removing all unique entries only where uniqueness is determined by two columns instead of one. I already tried various tweaks to the above answer but couldn't get any of them to work.
You are using SQL Server, so this is easier than in Access:
select A, B, C
from (select t.*, count(*) over (partition by A, B) as cnt
from t
) t
where cnt > 1;
This use of count(*) is as a window function. It is counting the number of rows with the same value of A and B. The final where just selects the rows that have more than one entry.
Another possible solution with EXISTS
SELECT a, b, c
FROM Table1 t
WHERE EXISTS
(
SELECT 1
FROM Table1
WHERE a = t.a
AND b = t.b
AND c <> t.c
)
It should be fast enough.
Output:
| A | B | C |
-------------
| 2 | 1 | 2 |
| 2 | 1 | 3 |
| 2 | 3 | 5 |
| 2 | 3 | 6 |
| 3 | 1 | 7 |
| 3 | 1 | 9 |
Here is SQLFiddle demo