Why my query with union operator returns only fields from first select? - sql

I need to get all values from table and values with condition for 'not null'.
So I make two SELECT statements.
select oa.dept_id, COUNT(oa.id) quantity, sum(oa.premium) 'sum'
from Table1 oa
Left Join Table2 od On od.id = oa.dept_id
group by oa.dept_id
Union all
select oa1.dept_id, COUNT(oa1.id) quantity1, sum(oa1.premium) 'sum1'
from Table1 oa1
Left Join Table2 od1 On od1.id = oa1.dept_id
where oa1.action is not null
group by oa1.dept_id
I expect result like this with 70 rows:
-----------------------------------------------
| dept.id | quantity | sum | quantity1 | sum1 |
-----------------------------------------------
I got result like this with 130 rows:
----------------------------
| dept.id | quantity | sum |
----------------------------

You need to use join
select a.dept_id, quantity, sum,quantity1,sum1
from
(
select oa.dept_id, COUNT(oa.id) quantity, sum(oa.premium) 'sum'
from Table1 oa
Left Join Table2 od On od.id = oa.dept_id
group by oa.dept_id
) a
join
(
select oa1.dept_id, COUNT(oa1.id) quantity1, sum(oa1.premium) 'sum1'
from Table1 oa1
Left Join Table2 od1 On od1.id = oa1.dept_id
where oa1.action is not null
group by oa1.dept_id
) b
on a.dept_id=b.dept_id

Related

How do I do mulitple joins on two databases tables

The goal is to join all the same values (the duplicates) together. Email, timestamp and daystamp.
I have created one join statement
SELECT history.email, history.timestamp, payment.timestamp,
history.daystamp, payment.daystamp
FROM history
FULL OUTER JOIN payment ON history.email = payment.email
ORDER BY history.email;
I have all the unique email addresses. How do I do the same for the timestamp and daystamp?
Can I do three outer joins in one statement?
Here are two methods that might be useful to adapt to your specific problem here although it's a little unclear without sample data.
Method 1:
SELECT A.column2
, B.column2
, C.column2
FROM
(
(SELECT month, column2 FROM table1) A
FULL OUTER JOIN
(SELECT month, column2 FROM table2) B on A.month= B.month
FULL OUTER JOIN
(SELECT month, column2 FROM table3) C on A.month= C.month
)
Method 2:
select
A.column2,
B.column2,
C.column2
from (
select distinct month from table1
union
select distinct month from table2
union
select distinct month from table3
) as X
left outer join table1 as A on A.month = X.month
left outer join table2 as B on B.month = X.month
left outer join table3 as C on C.month = X.month
Something like this?
SELECT
case when p.payment_id is not null then 'p' else 'h' end as tbl
, coalesce(h.email, p.email) as email
, coalesce(h.timestamp, p.timestamp) as timestamp
, coalesce(h.daystamp, p.daystamp) as daystamp
FROM history h
FULL JOIN payment p
ON h.email = p.email
AND h.timestamp = p.timestamp
AND h.daystamp is not distinct from p.daystamp
WHERE (h.history_id is null or p.payment_id is null)
ORDER BY coalesce(h.email, p.email);
tbl | email | timestamp | daystamp
:-- | :------------- | :------------------ | -------:
h | test2#mail.not | 2022-02-22 22:22:22 | 20220222
p | test2#mail.not | 2022-02-22 22:28:22 | 20220222
h | test3#mail.not | 2022-02-22 22:22:23 | 20220222
p | test4#mail.not | 2022-02-22 22:22:24 | 20220222
Test on db<>fiddle here

find the max for each value in SQL

i have tables like this
table 1
|cl.1|
| -- |
| a |
| b |
| c |
table 2
|cl.1|cl.2|para|
|----|---| --- |
| a | 3 | t |
| a | 3 | f |
| b | 2 | t |
| a | 1 | b |
| c | 4 | t |
| b | 7 | d |
i want to get the max value for each element in table1 from table2
and the different parameter
so the expecited tabel should be like this
|cl.1|max|para|
|----|---| --- |
| a | 3 | t |
| a | 3 | f |
| c | 4 | t |
| b | 7 | d |
You can try to compute all the maximums:
with Maxes as (
select cl1,
max(cl2) as cl2
from Table2
group by cl1)
and then join them with the original Table2, e.g.
with Maxes as (
select cl1,
max(cl2) as cl2
from Table2
group by cl1)
select t.*
from Table2 t join
Maxes m on (t.cl1 = m.cl1 and t.cl2 = m.cl2)
Depends on what features your RDBMS supports.
With Oracle you could do a CROSS APPLY to order table2 by descending cl2 and keep the top values (with ties):
select T1.c1, TM.maximum, TM.para
from Table1 T1
cross apply (
select *
from Table2 T2
where T2.c1 = T1.c1
order by T2.maximum descending
fetch first 1 row with ties
) TM
You can do the same in SQL Server with syntax select top 1 with ties instead of fetch first 1 row with ties.
Another option could be to use Analytical Functions to rank the results per col1 and then keep only the first ones.
select T.c1, T.maximum, T.para
from (
select
T1.c1, T2.maximum, T2.para,
rank() over (partition by T1.c1 order by T2.maximum desc) r
from T1
join T2 on T1.c1 = T2.c2
) T
where T.r = 1
Less stylish and probably(?) less performant would be computing the maximum for each c1 and then doing an equality:
select T1.c1, T2.maximum, T2.para
from T1
join T2 on T1.c1 = T2.c1
where T2.maximum = (select max(maximum) from T2 where c1 = T1.c1)
If you are trying to get the max tl.1 and if for the same values it is equal, you could try:
SELECT *
FROM table2
WHERE cl_2 in ( SELECT MAX(cl_2)
FROM table2
group by cl_1
);
Result:
cl_1 cl_2 para
a 3 t
a 3 f
c 4 t
b 7 d
Tested on MySQL : https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=42a6bc20622a210b18101588540995ec
You could use a join , but it makes no difference:
SELECT t1.cl_1,t2.cl_2,t2.para
FROM table2 t2
INNER JOIN table1 t1 on t2.cl_1=t1.cl_1
WHERE t2.cl_2 in (SELECT MAX(cl_2) FROM table2 group by cl_1 );
Demo: https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=4b2eed9bcee3532cc7c4e7b3862bc3ef
DENSE_RANK can be used to get whole rows that have a maximum of something within a partition.
Because when sorted descending, the top 1 will have rank 1.
select cl_1, cl_2, para
from
(
select cl_1, cl_2, para
, dense_rank() over (partition by cl_1 order by cl_2 desc) as rnk
from table1 t1
join table2 t2 using (cl_1)
) q
where rnk = 1
Use a CTE to get the max values, then select the rows with those values:
with maxes as
(
select t1.[cl.1]
, max(t2.[cl.2]) max_val
from table1 t1
inner join table2 t2
on t1.[cl.1] = t2.[cl.1]
group by t1.[cl.1]
)
select t1.[cl.1]
, t2.[cl.2]
, t2.para
from table1 t1
inner join table2 t2
on t1.[cl.1] = t2.[cl.1]
where t2.[cl.2] = (select m.max_val from maxes m where m.[cl.1] = t1.[cl.1])
This can also be achieved by joining the CTE:
with maxes as
(
select t1.[cl.1]
, max(t2.[cl.2]) max_val
from table1 t1
inner join table2 t2
on t1.[cl.1] = t2.[cl.1]
group by t1.[cl.1]
)
select t1.[cl.1]
, t2.[cl.2]
, t2.para
from table1 t1
inner join table2 t2
on t1.[cl.1] = t2.[cl.1]
inner join maxes m
on t2.[cl.2] = m.max_val

How to return 1 row instead of 3 when one column has different data

I have 3 rows of data returned from a query
OrderId | OtherId
--------+---------
1234 | 444
1234 | 555
1234 | 666
How to return data in this format
OrderId | OtherId | OtherId2 | OtherId
--------+---------+----------+--------
1234 | 444 | 555 | 666
Can I use Distinct for this problem?
EDIT
The result set comes from a query such as
left join (
Select distinct
o.id
,OL2.db
,case
when i.cust = 'cust2' then
case
when
lower(pdf.dept) not like 'abc%' or pdf.dept is null
then 'Yes'
else'No'
end
else 'Yes'
end as 'Show'
,otherId
from order o with(nolock)
Join instance i with(nolock) on i.id = o.id
Join orderLine ol with(nolock) on ol.id = o.SocialNetworker_Order_InstanceId
and ol.id = o.id
join product p with(nolock) on o.id = p.id
and ol.id = p.id
left join productEx pdf with(nolock) on p.id = pdf.id
and o.id = pdf.id
Where i.cust in ('cust1')
) ol2 on OL2.id = sno.id
and OL2.id2 = sno.id2
and i.db = cc.db
How to work solution into the above code?
You can use row_number() and conditional aggregation:
select orderid,
max(case when seqnum = 1 then otherid end) as otherid_1,
max(case when seqnum = 2 then otherid end) as otherid_2,
max(case when seqnum = 3 then otherid end) as otherid_3
from (select t.*, row_number() over (partition by orderid order by otherid) as seqnum
from t
) t
group by orderid;
Use an outer join with cascading join conditions:
select t1.OrderId, t1.OtherId OtherId1, t2.OtherId OtherId2, t3.OtherId OtherId3
from orders t1
left join orders t2 on t2.OrderId = t1.OrderId
and t2.OtherId > t1.OtherId
left join orders t3 on t3.OrderId = t2.OrderId
and t3.OtherId > t2.OtherId
If there are less than 3 other ids, the right-most columns will be null.
This query will work on pretty much any database.

inner join select results with a table

How to join select results with another table?
Example: generate 2-column table of aggregate value of each product type
SELECT product_type, SUM(value) AS total from table1
WHERE something_something_is_true
GROUP BY product_type;
Another table named table2 has textual descriptions of product types
product_type | description | more columns
---------------------------------------
1 | ....................
2 | ....................
How to join description column to the above selection results so that the resulting table looks something like this?
product_type | total | description
---------------------------------
1 | 589 | stationary
2 | 234 | closing
You can use a subquery as a table expression:
SELECT t1.product_type, total, description
FROM (SELECT product_type, SUM(value) AS total
FROM table1
WHERE something_something_is_true
GROUP BY product_type) t1
JOIN table2 t2 ON t1.product_type = t1.product_type
Use your query as a derived table and then join your description table to it.
select t1.*, t2.description
from (
SELECT product_type, SUM(value) AS total
from table1
WHERE ...
GROUP BY product_type
) t1
join table2 t2 on t1.product_type = t2.product_type
You can just do:
SELECT t1.product_type, SUM(value) AS total,
MAX(t2.description)
FROM table1 t1 LEFT JOIN
table2 t2
ON t2.product_type = t1.product_type
WHERE something_something_is_true
GROUP BY t1.product_type;

Count Customers based on item master

I need you to help me on writing two queries in SQL Server 2008 that shows the following information based on item master:
Brand wise count on customer master plus customer who purchased the brand
Item Wise count of customer master plus customer who purchased the item
Here the link that shows the table information and the query which I tried.
Click here to view the table in SQL Fiddle
SELECT
brandname,
division,
route,
DivisionTotalCustomersCount = MAX(DivisionTotalCustomersCount),
RouteTotalCustomersCount = MAX(RouteTotalCustomersCount),
PurchasedCustomersCount = SUM(PurchasedCustomersCount)
FROM
(SELECT
i.brandname,
c.division,
c.route,
DivisionTotalCustomersCount =
(SELECT COUNT(distinct x.CustomerID)
FROM CustomerMaster x
WHERE x.division = c.division),
RouteTotalCustomersCount =
(SELECT COUNT(distinct x.CustomerID)
FROM CustomerMaster x
WHERE x.Route = c.route),
PurchasedCustomersCount = count(distinct C.CustomerID)
FROM CustomerMaster c
LEFT OUTER JOIN SalesData s on c.CustomerID = s.CustomerID
right outer join ItemMaster i on s.item = i.itemcode
GROUP BY i.brandname, c.division, c.route) A
GROUP BY
brandname, division, route
ORDER BY 1
Result Should as below
Excelsheet
I think you need to go reconsider the report and maybe splitting it out into multiple reports.
It does not make sense to have a route count as well as a divisional count if they are counting things at different levels of aggregation. So have a route count and division count report.
Either way, division and route is going to be null for 100PLUS because there are no customers for that brand which means there is no route or division info available.
--Division Count
SELECT BrandName, Division, COUNT(CustomerMaster.CustomerID) [Customer Count]
FROM ItemMaster LEFT OUTER JOIN
SalesData ON ItemMaster.BrandName = SalesData.Brand LEFT OUTER JOIN
CustomerMaster ON SalesData.CustomerID = CustomerMaster.CustomerID
GROUP BY BrandName, Division
--Route Count
SELECT BrandName, Route, Division, COUNT(CustomerMaster.CustomerID) [Customer Count]
FROM ItemMaster LEFT OUTER JOIN
SalesData ON ItemMaster.BrandName = SalesData.Brand LEFT OUTER JOIN
CustomerMaster ON SalesData.CustomerID = CustomerMaster.CustomerID
GROUP BY BrandName, Route, Division
Using your sqlfiddle data there are 25 sales records & 18 distinct brand/ division/ route/ customer records and there are no sales invloving 100PLUS
select
B.BrandName
, V.Division
, coalesce(Brand_count,0) as Brand_count
, coalesce(Division_count,0) as Division_count
from (select distinct BrandName from ItemMaster) as B
cross join (select distinct Division from CustomerMaster) as V
left join (
select
Brand
, Division
, sum(cust_count) over (partition by Brand) as Brand_count
, sum(cust_count) over (partition by Division) as Division_count
from (
select
S.Brand
, C.Division
, count(distinct S.CustomerID) cust_count
from salesdata as S
inner join CustomerMaster as C
on S.CustomerID = C.CustomerID
inner join ItemMaster as I
on S.item = I.ItemCode
group by
S.Brand
, C.Division
) as S
) as D
on B.BrandName = D.Brand
and V.Division = D.Division
order by
B.BrandName
, V.Division
;
| BRANDNAME | DIVISION | BRAND_COUNT | DIVISION_COUNT |
|-----------|----------|-------------|----------------|
| 100PLUS | Dubai | 0 | 0 |
| 100PLUS | RAK | 0 | 0 |
| KITCO | Dubai | 9 | 11 |
| KITCO | RAK | 9 | 7 |
| Red Bull | Dubai | 9 | 11 |
| Red Bull | RAK | 9 | 7 |
http://sqlfiddle.com/#!3/fecb0/27
All Credit to #kevriley
select
A.BrandName,
B.Division,
B.Route,
B.DivisionTotalCustomers,
B.RouteTotalCustomers,
isnull(C.PurchasedCustomersCount,0) as PurchasedCustomersCount
from
(
select distinct
BrandName, Route, Division
from dbo.ItemMaster
cross join dbo.CustomerMaster
) A
join
(
select distinct
Division,
Route,
DENSE_RANK() over (partition by Division order by c.CustomerID asc) + DENSE_RANK() over (partition by Division order by c.CustomerID desc) - 1 as DivisionTotalCustomers ,
DENSE_RANK() over (partition by ROUTE order by c.CustomerID asc) + DENSE_RANK() over (partition by ROUTE order by c.CustomerID desc) - 1 as RouteTotalCustomers
from CustomerMaster c
left join SalesData s on c.CustomerID = s.CustomerID
) B on B.Division = A.Division and B.Route = A.Route
left join
(
select
s.brand,
c.division,
c.route,
PurchasedCustomersCount = count(distinct C.CustomerID)
FROM CustomerMaster c
JOIN SalesData s on c.CustomerID = s.CustomerID
--join ItemMaster i on s.item = i.itemcode
GROUP by s.brand, c.division, c.route
) C on A.Brandname = C.Brand and C.Division = A.Division and C.Route = A.Route
See the same on SQL Fiddle
Select B.Brandname,B.Division,C AS DivisionTotalCustomerCount,
ISNULL(T.Count,0) AS PURCHASEDCUSTOMERSCOUNT
from
(
Select CM.Division,M.BrandName,COUNT(distinct CM.CustomerID) AS C
from dbo.CustomerMaster CM
CROSS JOIN ItemMaster M
GROUP BY CM.Division,M.BrandName
)B
LEFT JOIN
(Select Division,Brand,COUNT(Distinct C.CustomerID) As Count from CustomerMaster C
JOIN salesdata D
On C.CustomerID=D.CustomerID
where D.Brand='Red Bull'
GROUP BY Division,Brand
)T
ON B.Brandname=T.Brand
and B.Division=T.Division
Order by 1,2