Query is not working accordingly in postgresql - sql

Select sum(num) as num, sum(numbr) as numbr
from
(
(Select 0 as num)
union all
(Select 1 as num)
) t,
(
(Select 2 as numbr)
union all
(Select 3 as numbr)
) t1
giving result:
num numbr
2 10
But the correct result should be
num numbr
1 5

You are doing the cross product of a table containing 0 and 1, and a table containing 2 and 3. Try removing the sums:
Select num, numbr as numbr from
(
(Select 0 as num)
union all
(Select 1 as num))t,
((Select 2 as numbr)
union all
(Select 3 as numbr)
)t1
This gives you:
0;2
0;3
1;2
1;3
Which will correctly sum to 2 and 10.

That happens because you are CROSS JOINING , every record connect to every record with out a relation condition, which means that in this case, your join becomes this:
NUM | NUMBR
0 2
0 3
1 2
1 3
Which SUM(NUM) = 2 and SUM(NUMBR) = 10 .
When joining, you have to specify the relation condition unless this is what you want.
Note: You are using implicit join syntax(comma separated) , you should avoid that and use the explicit syntax and this will help you make sure you are using a relation condition (by the ON clause):
Select sum(num) as num, sum(numbr) as numbr
from
(
(Select 0 as num)
union all
(Select 1 as num)
) t
INNER JOIN
(
(Select 2 as numbr)
union all
(Select 3 as numbr)
) t1
ON(t.<Col> = t1.<Col1>)

Select num, numbr as numbr
from
(
(Select 0 as num)
union all
(Select 1 as num)
) t,
(
(Select 2 as numbr)
union all
(Select 3 as numbr)
) t1
Gives you the cartessian product of tables.
| Num | Number |
|-----|--------|
| 0 | 2 |
| 0 | 3 |
| 1 | 2 |
| 1 | 3 |
Therefore the sum of these are 2 and 10

Its correctly working as you wrote. If you want the result as you expected, try this:
Select sum(distinct num) as num, sum(distinct numbr) as numbr
from
(
(Select 0 as num)
union all
(Select 1 as num)
) t,
(
(Select 2 as numbr)
union all
(Select 3 as numbr)
) t1

Related

How to find most frequent code(varchar) from a table

I would like to find most frequent code within CodeID which is in same code_group from a table.
For example, from original table
ID CodeID Name Code Code_group
1 1 A 101 0
2 1 A 102 0
3 1 B 102 0
4 2 C 201 0
5 2 C 201 0
6 2 D 202 0
7 2 E 202 0
8 3 F 101 1
9 3 G 103 1
10 3 G 104 1
11 3 G 104 1
I want output like the below.
ID CodeID Name Code Code_group Selected_code
1 1 A 101 0 102
2 1 A 102 0 102
3 1 B 102 0 102
4 2 C 201 0 NULL
5 2 C 201 0 NULL
6 2 D 202 0 NULL
7 2 E 202 0 NULL
8 3 F 101 1 104
9 3 G 103 1 104
10 3 H 104 1 104
11 3 H 104 1 104
Even though code of 8th ID is same in CodeID: 1,it is not in the same Code_group.
So For CodeID: 1, Selected_code would be 102.
it must be counted within exactly same Code_group.
=======================================
I have tried it like the below. I should not use ID for this one.
From TableA
with m as
(
select
CodeID,
Name,
Code,
Code_group,
cnt,
Selected_code = ROW_NUMBER() over (partition by Code_group order by cnt desc)
from( select CodeID, Name, Code,Code_group
,count(*) over (partition by Code,CodeID) as cnt from tableA
group by CodeID, Name, Code, Code_group,
) as t
group by CodeID,
Name,
Code,
Code_group, cnt
)
select a.CodeID,
a.Name,
a.Code,
a.Code_group, b.Code as Selected_code, cnt
from(select
CodeID,
Name,
Code,
Code_group,Selected_code,
cnt
from m) as a left outer join
(select CodeID,
Name,
Code,
Code_group,Selected_code,
cnt
from m where selected_Code=1) as b on a.CodeID = b.CodeID and a.Code_Group = b.Code_Group
order by a.CodeID, a.Code_Group
The problem of this is
With statment makes my table distinct. It shows only one row if there is exactly same data such as ID 1,2.
Also, I cannot make NULL if there is exactly same frequencies.
What should I add to get my desired output?
Or is there any better approach for this?
CTE cte find the highest frequency code by Code_group and CodeID using dense_rank()
CTE selected check for any Code with same frequency and exclude them.
Final query just select from the original table and LEFT JOIN the selected
with
cte as
(
select Code_group, CodeID, Code
from
(
select Code_group, CodeID, Code,
r = dense_rank() over (partition by Code_Group, CodeID
order by count(*) desc)
from tableA
group by Code_group, CodeID, Code
) c
where c.r = 1
),
selected as
(
select Code_group, CodeID, Code
from
(
select Code_group, CodeID, Code,
cnt = count(*) over (partition by Code_group, CodeID)
from cte
) s
where s.cnt = 1
)
select a.*,
Selected_Code = s.Code
from tableA a
left join selected s on a.Code_Group = s.Code_Group
and a.CodeID = s.CodeID;
db<>fiddle demo

How put grouping variable to columns in SQL/

I have following dataset
and want to get this
How can I do it?
Using SQL Server, you can use a PIVOT, such as :
SELECT Time, [a],[b],[c]
FROM
(
SELECT time, [group],value
FROM dataset) d
PIVOT
(
SUM(value)
FOR [group] IN ([a],[b],[c])
) AS pvt
You can try it on the following fiddle.
Changed the column names to not conflict with reserved words. You would have to put them into single quotes otherwise.
WITH
-- the input
indata(grp,tm,val) AS (
SELECT 'a',1,44
UNION ALL SELECT 'a',2,22
UNION ALL SELECT 'a',3, 1
UNION ALL SELECT 'b',1, 1
UNION ALL SELECT 'b',2, 5
UNION ALL SELECT 'b',3, 6
UNION ALL SELECT 'c',1, 7
UNION ALL SELECT 'c',2, 8
UNION ALL SELECT 'c',3, 9
)
SELECT tm
, SUM(CASE grp WHEN 'a' THEN val END) AS a
, SUM(CASE grp WHEN 'b' THEN val END) AS b
, SUM(CASE grp WHEN 'c' THEN val END) AS c
FROM indata
GROUP BY tm
;
tm | a | b | c
----+----+---+---
1 | 44 | 1 | 7
2 | 22 | 5 | 8
3 | 1 | 6 | 9
select * from
(
select
time,[group],value
from yourTable
group by time,[group],value
)
as table
pivot
(
sum([value])
for [group] in ([a],[b],[c])
) as p
order by time
This is the result
for Vertica,
SELECT time
, SUM(value) FILTER (WHERE group = a) a
, SUM(value) FILTER (WHERE group = b) b
, SUM(value) FILTER (WHERE group = c) c
FROM yourTable
GROUP BY time

Split Columns into two equal number of Rows

I have the table structure below,
I need to merge the CouponNumber to two equal as CouponNumber1 and CouponNumber2 as shown in the figure
SELECT Name, MobileNumber, CouponNumber, IsDispatched, Status
FROM CouponInvoicePrescription
This is my query.
Try this:
WITH
input(ord,name,mobno,couponno,isdispatched,status) AS (
SELECT 0,'amar',8888888888,'CPever901',FALSE,1
UNION ALL SELECT 1,'amar',8888888888,'CP00005' ,FALSE,1
UNION ALL SELECT 2,'pt3' ,7777777777,'cp9090' ,FALSE,1
UNION ALL SELECT 3,'pt3' ,7777777777,'ev2' ,FALSE,1
UNION ALL SELECT 4,'pt3' ,7777777777,'cp9909' ,FALSE,1
UNION ALL SELECT 5,'pt3' ,7777777777,'cp10' ,FALSE,1
)
SELECT
name
, MAX(CASE ord % 2 WHEN 1 THEN couponno END) AS couponno1
, MAX(CASE ord % 2 WHEN 0 THEN couponno END) AS couponno2
, isdispatched
, status
FROM input
GROUP BY
ord / 2
, name
, isdispatched
, status
ORDER BY 1
-- out name | couponno1 | couponno2 | isdispatched | status
-- out ------+-----------+-----------+--------------+--------
-- out amar | CP00005 | CPever901 | f | 1
-- out pt3 | cp10 | cp9909 | f | 1
-- out pt3 | ev2 | cp9090 | f | 1
Try this:
SELECT * FROM
(
SELECT
sub.rn,
sub.Name,
sub.MobileNumber,
sub.CouponNumber as CouponNumber1,
LEAD(sub.CouponNumber,1) OVER (PARTITION BY sub.MobileNumber ORDER BY sub.rn) as CouponNumber2,
sub.IsDispatched,
sub.Status
FROM
(
SELECT
ROW_NUMBER() OVER (PARTITION by MobileNumber ORDER BY Name) as rn,
*
FROM
input
) sub
)
WHERE rn % 2 <> 0

count rows which have max value less than specified parameter

I want to find in my table, max value which is less than specified in parameter and get count of rows that have the same value as max value. For example in my table I have values: (4,1,3,1,4,4,10), and it is list of parameters in string "2,9,10,4". I have to split string to separate parameters. Base on this sample values I want to get something like that:
param | max value | count
2 | 1 | 2
9 | 4 | 3
10 | 4 | 3
4 | 3 | 1
And it is my sample query:
select
[param]
, max([val]) [max_value_by_param]
, max(count) [count]
from(
select
n.value as [param]
,a.val
, count(*) as [count]
from (--mock of table
select 1 as val union all
select 3 as val union all
select 4 as val union all
select 1 as val union all
select 3 as val union all
select 4 as val union all
select 4 as val union all
select 10 as val
) a
join (select [value] from string_split('2,9,10,4', ',')) n--list of params
on a.val < n.[value]
group by n.value, a.val
) tmp
group by [param]
Is it possible to do it better/easier ?
Here is a way to express this using apply:
select s.value as param, a.val, a.cnt
from string_split('2,9,10,4', ',') s outer apply
(select top (1) a.val, count(*) as cnt
from a
group by a.val
having a.val < s.value
order by a.val desc
) a;
Here is a db<>fiddle.
But the fastest method is probably going to be:
with av as (
select a.val, count(*) as cnt
from a
group by a.val
union all
select s.value, null as cnt
from string_split('2,9,10,4', ',') s
)
select val, a_val, a_cnt
from (select av.*,
max(case when cnt is not null then val end) over (order by val, (case when cnt is null then 1 else 2 end)) as a_val,
max(case when cnt is not null then cnt end) over (order by val, (case when cnt is null then 1 else 2 end)) as a_cnt
from av
) av
where cnt is null;
This only aggregates the data once and should return all parameters, even those with no preceding values in a.

How to write a cross tab query with median

Here's my table
ST NUM
1 1
1 2
1 2
2 1
2 2
2 2
3 2
3 8
I want to return a query where it returns the median of NUM for each ST
ST NUM
1 2
2 2
3 5
I already have a median function
SELECT
CONVERT(DECIMAL(10,2), (
(CONVERT (DECIMAL(10,2),
(SELECT MAX(num) FROM
(SELECT TOP 50 PERCENT num FROM dbo.t ORDER BY num ASC) AS H1)
+
(SELECT MIN(sortTime) FROM
(SELECT TOP 50 PERCENT num FROM dbo.t ORDER BY num DESC) AS H2)
))) / 2) AS Median
Any tips for how to do this?
try this
With
MedianResult
as
(
Select
ST,NUM ,
Row_Number() OVER(Partition by ST Order by NUM) as A,
Row_Number() OVER(Partition by ST Order by NUM desc) as B
from **YourTableName**
)
Select ST, Avg(NUM) as Median
From MedianResult
Where Abs(A-B)<=1
Group by ST