Select Distinct Records for min date - sql

I Have a query where In I need to select all the distinct ID's from the table, also need to select only the min(date) so that I get records that were inserted 1st and not ID's for all dates.
Basically this is what I am looking for -
Table 1 || Table 2-
ID || ID Date
1 || 1 11/11/2010
1 || 1 10/11/2010
3 || 3 12/01/2010
4 || 4 01/01/2010
4 || 4 02/01/2010
So i need to get all records from Table 2(table1.ID=table2.ID) which has the Minimum Date along with that ID
Result here would be
1 10/11/2010
3 12/01/2010
4 01/01/2010
Here is my query
select u.firstName,u.lastName ,count(*) as theCount
from tbl_appts_change_log c,tbl_appts a, tbl_users u
where c.appt_id=a.ID
and c.user_id=u.userID
and c.appt_id in ( select c.appt_id,min(c.date) from tbl_appts_change_log c, tbl_appts a
where c.appt_id=a.ID
and a.satellite_id='160' GROUP BY c.appt_id)
group by u.firstName,u.lastName
order by count(*) desc,u.firstName,u.lastName

maybe:
select u.firstName,u.lastName ,count(*) as theCount
from tbl_appts_change_log c
INNER JOIN tbl_appts a on c.appt_id=a.ID
INNER JOIN tbl_users u on c.user_id=u.userID
INNER JOIN ( select c.appt_id,min(c.date) as LastDate
from tbl_appts_change_log c
INNER JOIN tbl_appts a on c.appt_id=a.ID
Where a.satellite_id='160' GROUP BY c.appt_id) d
on c.appt_id = d.appt_id and c.date = d.LastDate
group by u.firstName,u.lastName
order by count(*) desc,u.firstName,u.lastName

I am ignoring your code as it seems to be a completely different scenario from what you have described in your question i.e Table1 and Table2. If all you want is the minimum date for each ID all you need is
SELECT T1.ID, MIN(T2.Date)
FROM Table1 T1
JOIN Table2 T2 ON T1.ID = T2.ID
GROUP BY T1.ID
But i am guessing what you really wanted was something like this?
Table 1 || Table 2-
ID || ID Date Desc
1 || 1 11/11/2010 AAA
1 || 1 10/11/2010 BBB
3 || 3 12/01/2010 CCC
4 || 4 01/01/2010 DDD
4 || 4 02/01/2010 EEE
And the expected result
1 10/11/2010 BBB
3 12/01/2010 CCC
4 01/01/2010 DDD
This is slightly more complicated than just doing a group by, and there are two ways to solve it. You could try both and see which one performs best
Method 1 : Using Row number
;WITH ResultCTE AS
(
SELECT T2.ID, T2.Date, T2.Desc,
RowNumber = ROW_NUMBER() OVER(PARTITION BY T2.ID ORDER BY T2.Date ASC)
FROM Table1 T1
JOIN Table2 T2 ON T1.ID = T2.ID
)
SELECT ID, Date, Desc
FROM ResultCTE
WHERE RowNumber = 1
Method 2: Nested query
;WITH ResultCTE AS
(
SELECT T2.ID, MIN(T2.Date) AS Date
FROM Table1 T1
JOIN Table2 T2 ON T1.ID = T2.ID
GROUP BY T2.ID
)
SELECT T.ID, T.Date, T.Desc
FROM Table2 T
JOIN ResultCTE R
ON R.ID = T.ID AND R.Date = T.Date

SELECT u.firstName,
u.lastName ,
COUNT(*) AS theCount
FROM tbl_appts_change_log c,
tbl_appts a,
tbl_users u
WHERE c.appt_id=a.ID
AND c.user_id =u.userID
AND a.satellite_id = '160'
AND c.date = (SELECT MIN(ci.date)
FROM tbl_appts_change_log ci,
tbl_appts ai
WHERE ci.appt_id = ai.ID
AND ci.appt_id = c.appt_id
AND ai.satellite_id= a.satellite_id
)
GROUP BY u.firstName,
u.lastName
ORDER BY COUNT(*) DESC,
u.firstName,
u.lastName

select u.firstName,u.lastName,count(*) as theCount,cm.MinDate
from (
select c.appt_id,min(c.date) as MinDate
from tbl_appts_change_log c, tbl_appts a
where c.appt_id=a.ID
and a.satellite_id='160'
GROUP BY c.appt_id
) cm
inner join tbl_appts_change_log c on cm.appt_id = c.appt_id and cm.MinDate = c.date
inner join tbl_appts a on c.appt_id=a.ID
inner join tbl_users u on c.user_id=u.userID
group by u.firstName,u.lastName
order by count(*) desc,u.firstName,u.lastName

If what you are looking for is-
Table 1 || Table 2-
ID || ID Date
1 || 1 11/11/2010
1 || 1 10/11/2010
3 || 3 12/01/2010
4 || 4 01/01/2010
4 || 4 02/01/2010
Try using this:
SELECT DISTINCT i1.id, i2.dt
FROM Table1 i1 JOIN (SELECT id, min(date) dt FROM Table2 GROUP BY id) i2
ON i1.id=i2.id

Is this what you're after?
select u.firstName,u.lastName ,count(*) as theCount
from tbl_appts_change_log c,tbl_appts a, tbl_users u
where c.appt_id=a.ID
and c.user_id=u.userID
and a.satellite_id = '160'
and c.date = (
select min(date)
from tbl_appts_change_log c, tbl_appts a
where c.appt_id = a.id
and a.satellite_id = '160'
)
group by u.firstName,u.lastName
order by count(*) desc,u.firstName,u.lastName

Related

How to group complicated condition in sql

I'd like to group by region where there are customerswho has type=a
region customer type score
A a a 1
A b b 2
A c a 3
B d c 4
B e d 5
C f a 6
C g c 7
Therefore after first step
region customer type score
A a a 1
A b b 2
A c a 3
C f a 6
C g c 7
And then I groupby in region
region sum(score)
A 6
C 13
also I'd like to extract customer whose type=a
region customer type
A a a
A c a
C f a
Then I'd like to merge above.
My desired result is like following
customer sum_in_region
a 6
c 6
f 13
Are there any way to achieve this?
My work is till the second step..
How can I proceed further?
SELECT t1.region,t1.customer, t1.type, t1.score
FROM yourTable t1
WHERE EXISTS (SELECT 1
FROM yourTable t2
WHERE t2.region = t1.region
AND t2.type = 'a');
Thanks
Join the table to a derived table that does your first two steps.
SELECT t3.customer,
x1.score
FROM yourtable t3
INNER JOIN (SELECT t1.region,
sum(score) score
FROM yourtable t1
WHERE EXISTS (SELECT *
FROM yourtable t2
WHERE t2.region = t1.region
AND t2.type = 'a')
GROUP BY t1.region) x1
ON x1.region = t3.region
WHERE t2.type = 'a';
You could use the windows functions to get your result; the first step filters for only rows where type is a, based on the region. The second step then gets the sum of scores, based again on the region, before selecting only customer and sum columns :
with filter_type_a as
(select region, customer, type, score
from
(select *,
sum(type=="a") over (partition by region) as counter
from your_table)
where counter > 0)
select customer, sum_region
from
(select customer, type,
sum(score) over (partition by region) as sum_region
from filter_type_a)
where type=="a";
You can use below query:
SQLFiddle
with country_tmp as
(SELECT t1.region,t1.customer, t1.type, t1.score
FROM country t1
WHERE EXISTS (SELECT 1
FROM country t2
WHERE t2.region = t1.region
AND t2.type = 'a'))
select y.customer, x.score from
(select a.region, sum(a.score) score from (
SELECT t1.region,t1.customer, t1.type, t1.score
FROM country_tmp t1) a
group by region) x , (SELECT t1.region,t1.customer, t1.type
FROM country_tmp t1
Where t1.type = 'a') y where x.region = y.region;

Need Full Outer Join without having Cross Join

Need to join two table without having cross join between them.
The join condition need to be made on Tabl.month = Tab2.month
Input
Table1 Table2
Month ID Month ID
1 a 1 a
1 b 1 b
1 c 2 g
2 d 3 i
2 e 3 j
3 f 3 k
Output:
Month_Tab1 ID_Tab1 Month_Tab2 ID_Tab2
1 a 1 a
1 b 1 b
1 c Null Null
2 d 2 g
2 e Null Null
3 f 3 i
Null Null 3 j
Null Null 3 k
The above o/p is required, without cross join, have tried full outer but cross join is happening as the ID is duplicate in both Tables. Left/Right join also cannt be applicable as either of the table might have larger set of ID's.
You want a full join, but with row_number() to identify the matches:
select t1.month month_tab1, t1.id id_tab1, t2.month month_tab2, t2.id id_tab2
from (
select t.*, row_number() over(partition by month order by id) rn from table1 t
) t1
full join (
select t.*, row_number() over(partition by month order by id) rn from table2 t) t2
on t2.month = t1.month and t2.rn = t1.rn
You can use a full outer join:
select
a.month,
a.id,
b.month,
b.id
from (
select month, id,
row_number() over(partition by month order by id) as n
from table1
) a
full outer join (
select month, id,
row_number() over(partition by month order by id) as n
from table2
) b on b.month = a.month and b.n = a.n
order by coalesce(a.month, b.month), coalesce(a.n, b.n)

Optimizing SQL query having DISTINCT keyword and functions

I have this query that generates about 40,000 records and the execution time of this query is about 1 minute 30 seconds.
SELECT DISTINCT
a.ID,
a.NAME,
a.DIV,
a.UID,
(select NAME from EMPLOYEE where UID= a.UID and UID<>'') as boss_id,
(select DATE(MAX(create_time)) from XYZ where XYZ_ID= 1 and id = a.ID) as TERM1,
(select DATE(MAX(create_time)) from XYZ where XYZ_ID= 2 and id = a.ID) as TERM2,
(select DATE(MAX(create_time)) from XYZ where XYZ_ID= 3 and id = a.ID) as TERM3,
(select DATE(MAX(create_time)) from XYZ where XYZ_ID= 4 and id = a.ID) as TERM4,
(select DATE(MAX(create_time)) from XYZ where XYZ_ID= 5 and id = a.ID) as TERM5,
(select DATE(MAX(create_time)) from XYZ where XYZ_ID= 6 and id = a.ID) as TERM6,
(select DATE(MAX(create_time)) from XYZ where XYZ_ID= 7 and id = a.ID) as TERM7,
(select DATE(MAX(create_time)) from XYZ where XYZ_ID= 8 and id = a.ID) as TERM8
FROM EMPLOYEE a
WHERE ID LIKE 'D%'
I tried using group by, different kinds of join to improve the execution time but couldn't succeed.Both the tables ABC and XYZ are indexed.
Also, I think that the root cause of this problem is either the DISTINCT keyword or the MAX function.
How can I optimize the above query to bring down the execution time to at least less than a minute?
Any help is appreciated.
Query is not tested, this is just an idea on how you could get this done in two different ways.
(SQL Server solutions here)
Using LEFT JOIN for each ID should look something like this:
SELECT a.ID,
a.NAME,
a.DIV,
a.UID,
b.Name as boss_id,
MAX(xyz1.create_time) as TERM1,
MAX(xyz2.create_time) as TERM2,
MAX(xyz3.create_time) as TERM3,
MAX(xyz4.create_time) as TERM4,
MAX(xyz5.create_time) as TERM5,
MAX(xyz6.create_time) as TERM6,
MAX(xyz7.create_time) as TERM7,
MAX(xyz8.create_time) as TERM8
FROM EMPLOYEE a
JOIN EMPLOYEE b on a.UID = b.UID and b.UID <> ''
LEFT JOIN XYZ xyz1 on a.ID = xyz1.ID and xyz1.XYZ_ID = 1
LEFT JOIN XYZ xyz2 on a.ID = xyz2.ID and xyz1.XYZ_ID = 2
LEFT JOIN XYZ xyz3 on a.ID = xyz3.ID and xyz1.XYZ_ID = 3
LEFT JOIN XYZ xyz4 on a.ID = xyz4.ID and xyz1.XYZ_ID = 4
LEFT JOIN XYZ xyz5 on a.ID = xyz5.ID and xyz1.XYZ_ID = 5
LEFT JOIN XYZ xyz6 on a.ID = xyz6.ID and xyz1.XYZ_ID = 6
LEFT JOIN XYZ xyz7 on a.ID = xyz7.ID and xyz1.XYZ_ID = 7
LEFT JOIN XYZ xyz8 on a.ID = xyz8.ID and xyz1.XYZ_ID = 8
WHERE a.ID LIKE 'D%'
GROUP BY a.ID, a.NAME, a.DIV, a.UID, b.Name
Using PIVOT would look something like this:
select * from (
SELECT DISTINCT
a.ID,
a.NAME,
a.DIV,
a.UID,
b.NAME as boss_id,
xyz.xyz_id,
xyz.create_time
FROM EMPLOYEE a
JOIN EMPLOYEE b on a.UID = b.UID and b.UID <> ''
LEFT JOIN (SELECT DATE(MAX(create_time)) create_time, XYZ_ID, ID
from XYZ
where XYZ_ID between 1 and 8
group by XYZ_ID, ID) xyz on a.ID = xyz1.ID
WHERE a.ID LIKE 'D%') src
PIVOT (
max(create_time) for xyz_id IN (['1'], ['2'], ['3'], ['4'],
['5'], ['6'], ['7'], ['8'])
) PIV
Give it a shot
I would recommend group by and conditional aggregation:
SELECT e.ID, e.NAME, e.DIV, e.UID,
DATE(MAX(CASE WHEN XYZ_ID = 1 THEN create_time END)) as term1,
DATE(MAX(CASE WHEN XYZ_ID = 2 THEN create_time END)) as term2,
DATE(MAX(CASE WHEN XYZ_ID = 3 THEN create_time END)) as term3,
DATE(MAX(CASE WHEN XYZ_ID = 4 THEN create_time END)) as term4,
DATE(MAX(CASE WHEN XYZ_ID = 5 THEN create_time END)) as term5,
DATE(MAX(CASE WHEN XYZ_ID = 6 THEN create_time END)) as term6,
DATE(MAX(CASE WHEN XYZ_ID = 7 THEN create_time END)) as term7,
DATE(MAX(CASE WHEN XYZ_ID = 8 THEN create_time END)) as term8
FROM EMPLOYEE e LEFT JOIN
XYZ
ON xyz.ID = e.id
WHERE e.ID LIKE 'D%'
GROUP BY e.ID, e.NAME, e.DIV, e.UID;
I don't understand the logic for boss_id, so I left that out. This should improve the performance significantly.

Different output when using count and group by

When trying to get a count of IDs I get a different answer when grouping by day vs when I am not.
select cv.CONV_DAY, count(distinct cv.CLICK_ID)
from
clickcache.click cc
right join(
select distinct cv.CLICK_ID, cv.CONV_DAY, cv.PIXEL_ID
from clickcache.CONVERSION cv
where cv.CLICK_ID IS NOT NULL) cv ON cv.CLICK_ID = cc.ID
where cc.ADV_ACCOUNT_ID = 25176
and cv.CONV_DAY between '2016-8-01' AND '2016-08-07'
and AMP_CLICK_STATUS_ID = 1
AND pixel_id IN
(SELECT DISTINCT conversion_pixel_id
FROM
ampx.campaign_event_funnel ef
JOIN ampx.campaign cp ON
cp.id = ef.campaign_id
AND cp.campaign_status_id = 1
WHERE
ef.account_id IN(25176)
AND include_optimization = 1 )
group by 1
order by 1 asc
This yields 170 which is the correct answer and the I want. This, on the other hand, displays 157.
select count(distinct cv.CLICK_ID)
from
clickcache.click cc
right join(
select distinct cv.CLICK_ID, cv.CONV_DAY, cv.PIXEL_ID
from clickcache.CONVERSION cv
where cv.CLICK_ID IS NOT NULL) cv ON cv.CLICK_ID = cc.ID
where cc.ADV_ACCOUNT_ID = 25176
and cv.CONV_DAY between '2016-8-01' AND '2016-08-07'
and AMP_CLICK_STATUS_ID = 1
AND pixel_id IN
(SELECT DISTINCT conversion_pixel_id
FROM
ampx.campaign_event_funnel ef
JOIN ampx.campaign cp ON
cp.id = ef.campaign_id
AND cp.campaign_status_id = 1
WHERE
ef.account_id IN(25176)
AND include_optimization = 1 )
My question is why do I get this discrepancy and how to fix it to get a proper count?
Thank you!
Your count dependents from right query, maybe you have duplicate row?
example
table1
id name value
1 2 3
table2
id name value
1 4 5
2 6 3
1 6 3
right join tables on value get result
select * from table1 a right join table2 b on a.value = b.value
1 2 3 2 6 3
1 2 3 1 6 3
select count(distinct a.value)
from (select a.id, a.name, a.value, b.id, b.name, b.value
from table1 a right join table2 b on a.value = b.value)
result is 1
select b.id, count(distinct a.value)
from (select a.id, a.name, a.value, b.id, b.name, b.value
from table1 a right join table2 b on a.value = b.value group)
group by b.id
result is two rows
2 1
1 1
My guess is that, you have a problem for this reason.

four queries in one result - oracle

I have four queries.
1.result: Count() | Nazev
result: Count() | Nazev
result: Ode_dne_včetně | Do_dne_včetně | Nazev_organizace | Pocet
result: Nazev | Create_uzivatel | create_cas
I want to have only one result after one click. In this way:
Count() | Nazev | Count() | Nazev | Ode_dne_včetně | Do_dne_včetně | Nazev_organizace | Pocet | Nazev | Create_uzivatel | create_cas
Is it possible?
--first
select count(*),subjekt.nazev from osoba,subjekt where
osoba.ID_PATRI_DO=subjekt.ID group by subjekt.nazev order by
subjekt.nazev;
--second
select count(*),subjekt.nazev from ZADAVACI_POSTUP,subjekt where
ZADAVACI_POSTUP.id_zadavatel=subjekt.ID group by subjekt.nazev order by
subjekt.nazev;
--third
select max(trunc(sysdate)-6) ode_dne_včetně, max(trunc(sysdate))
do_dne_včetně,nazev_organizace,count(*) pocet
from(
select to_char(t.popis) popis_typu,subj.nazev nazev_organizace,
u.username,u.nazev, a.datumzapisauditu
,to_char(a.datumzapisauditu,'DD.MM.YYYY') datum , a.id
from d$caudit a
join cuzivatel u on u.id= a.id_uzivatel
join osoba os on u.id_osoba_bridge = os.id
join t$subjekt subj on subj.id = os.id_patri_do
left join d$caudittyp t on t.id=a.id_audittyp
where datumzapisauditu between trunc(sysdate)-7 AND trunc(sysdate)
order by a.datumzapisauditu desc
)
group by nazev_organizace order by nazev_organizace ;
--fourth
select sb.nazev, lg.create_uzivatel, lg.create_cas from Aplikacni_log lg
join zadavaci_postup zp on zp.id = lg.id_zp
join subjekt sb on sb.id = zp.id_zadavatel
where lg.create_cas > to_date('08.11.2014', 'DD.MM.YYYY')
order by sb.nazev asc
You can use subquery refactoring to achieve this.
Edit1:- subjekt.nazev is the relationship between the four queries then
you can add WHERE first_qry.nazev=second_qry.nazev and similar relationship with remaining queries.
with first_qry as (select count(*),subjekt.nazev from osoba,subjekt where
osoba.ID_PATRI_DO=subjekt.ID group by subjekt.nazev order by
subjekt.nazev),
second_qry as (select count(*),subjekt.nazev from ZADAVACI_POSTUP,subjekt where
ZADAVACI_POSTUP.id_zadavatel=subjekt.ID group by subjekt.nazev order by
subjekt.nazev),
third_qry as ( select max(trunc(sysdate)-6)
ode_dne_včetně, max(trunc(sysdate))
do_dne_včetně,nazev_organizace,count(*) pocet
from(
select to_char(t.popis) popis_typu,subj.nazev nazev_organizace,
u.username,u.nazev, a.datumzapisauditu
,to_char(a.datumzapisauditu,'DD.MM.YYYY') datum , a.id
from d$caudit a
join cuzivatel u on u.id= a.id_uzivatel
join osoba os on u.id_osoba_bridge = os.id
join t$subjekt subj on subj.id = os.id_patri_do
left join d$caudittyp t on t.id=a.id_audittyp
where datumzapisauditu between trunc(sysdate)-7
AND trunc(sysdate)
order by a.datumzapisauditu desc
)
group by nazev_organizace order by nazev_organizace),
fourth_qry as (select sb.nazev, lg.create_uzivatel,
lg.create_cas from Aplikacni_log lg
join zadavaci_postup zp on zp.id = lg.id_zp
join subjekt sb on sb.id = zp.id_zadavatel
where lg.create_cas > to_date('08.11.2014', 'DD.MM.YYYY')
order by sb.nazev asc)
select distinct a.*,b.*,c.*,d.*
from first_qry a ,second_qry b,third_qry c,fourth_qry d
Yesterday you asked a similar question and I answered it with this answer.
You can use the same method of using Union or Union all and just select null for each column where you do not have a result
select count(*) AS subjekt_count,subjekt.nazev ,null,null,null,null,null,null
--null columns represent the results from the other queries
from osoba,subjekt
where osoba.ID_PATRI_DO=subjekt.ID
group by subjekt.nazev
UNION ALL
select null, null,count(*) AS subjekt_nazev_count,subjekt.nazev,null,null,null,null
from ZADAVACI_POSTUP,subjekt where
ZADAVACI_POSTUP.id_zadavatel=subjekt.ID
group by subjekt.nazev
---and so on
There are other methods using a WITH statement but you need a common key between the statements and I am not clear on whether your queries are four exclusive queries to the same tables or four overlapping queries. Do you expect duplicates in the results?
All your queries contain column nazev which is grouping and order key so I assumed that this is the field joining results.
If this is so, then you can use follwoing SQL. If this is not what you wanted then please edit question, attach some data, table definitions, preferably as SQL Fiddle and precisely explain your request.
SQLFiddle
with q1 as (select count(*) cnt, subjekt.nazev
from osoba,subjekt where osoba.ID_PATRI_DO=subjekt.ID
group by subjekt.nazev ),
q2 as (select count(*) cnt, subjekt.nazev
from ZADAVACI_POSTUP, subjekt
where ZADAVACI_POSTUP.id_zadavatel=subjekt.ID
group by subjekt.nazev ),
q3 as (select max(trunc(sysdate)-6) ode_dne_vcetne,
max(trunc(sysdate)) do_dne_vcetne, nazev_organizace nazev, count(*) pocet
from (
select to_char(t.popis) popis_typu,subj.nazev nazev_organizace,
u.username, u.nazev, a.datumzapisauditu,
to_char(a.datumzapisauditu,'DD.MM.YYYY') datum, a.id
from d$caudit a
join cuzivatel u on u.id= a.id_uzivatel
join osoba os on u.id_osoba_bridge = os.id
join t$subjekt subj on subj.id = os.id_patri_do
left join d$caudittyp t on t.id=a.id_audittyp
where datumzapisauditu between trunc(sysdate)-7 and trunc(sysdate) )
group by nazev_organizace),
q4 as (select sb.nazev, lg.create_uzivatel, lg.create_cas
from aplikacni_log lg join zadavaci_postup zp on zp.id = lg.id_zp
join subjekt sb on sb.id = zp.id_zadavatel
where lg.create_cas > to_date('08.11.2014', 'DD.MM.YYYY') )
select nazev, q1.cnt cnt1, q2.cnt cnt2, q3.ode_dne_vcetne, q3.do_dne_vcetne,
q3.pocet, q4.create_uzivatel, q4.create_cas
from q1 left join q2 using (nazev) left join q3 using (nazev) left join q4 using (nazev)
order by nazev, create_cas
Output for sample data:
NAZEV CNT1 CNT2 ODE_DNE_VCETNE DO_DNE_VCETNE POCET CREATE_UZIVATEL CREATE_CAS
---------- ---- ---- -------------- ------------- ----- --------------- ----------
SUBJEKT1 1 1 1 2015-03-20
SUBJEKT2 2 1 1 2015-03-20