Getting a column with count from a nested query - count

as a newbie in SQL I am lost regarding nested queries.
I am trying to achieve the following: getting a table grouped by month with a count from all values of a column, then the same count filtered by status.
So for instance in January I could have the following result:
Jan 22 Count= 100 Count with Status filter= 57
I tried several variations along these lines:
SELECT
FORMAT ( [CreatedDate.table2] , 'yyyyMM' ) as create_month,
RecordTypeName__c,
count(*) as count_all,
count_filtered
FROM
(SELECT
FORMAT ( [CreatedDate] , 'yyyyMM' ) as create_month,
RecordTypeName__c,
Count(*) AS count_filtered
FROM DM_AccessNoAgg.DimLead
WHERE [CreatedDate] >= '2022-01-01'
AND [Status]='Qualifiziert'
GROUP BY RecordTypeName__c,FORMAT ( [CreatedDate] , 'yyyyMM' )
)
Basically I am using the same value in both cases, just that the second count has to be filtered. What's the best method to get this done?
Thanks for your help!
Pauline.

Related

ORA-00932: inconsistent datatypes: expected DATE got NUMBER

I am using Oracle 11g and running the following query in oracle toad:
WITH
CTEDevices (CREATED_ON, CUSTOMER_INFO_ID, DEVICE_MAKE, DEVICE_Model) AS (
SELECT
Trunc(RD.CREATED_ON),
RD.CUSTOMER_INFO_ID,
RD.DEVICE_MAKE,
RD.DEVICE_Model
FROM Schema.Table1 RD
WHERE RD.PARAM_CHANNEL_ID = 1
AND RD.CREATED_ON >= '01-may-2022'
AND RD.CREATED_ON <= '02-may-2022'
GROUP BY
Trunc(RD.CREATED_ON),
RD.CUSTOMER_INFO_ID,
RD.DEVICE_MAKE,
RD.DEVICE_Model
),
CTERegistration (CREATED_ON, CUSTOMER_INFO_ID, DEVICE_MAKE, DEVICE_Model) AS
(
SELECT
CI.Customer_Info_Id,
Trunc(CI.created_on),
'CI.DEVICE_MAKE',
'CI.DEVICE_Model'
FROM Schema.Table2 CI
Where CI.CUSTOMER_TYPE = 'A'
AND CI.CREATED_ON >= '01-may-2022'
AND CI.CREATED_ON <= '02-may-2022'
)
SELECT
CTEDevices.CREATED_ON, CTEDevices.CUSTOMER_INFO_ID, CTEDevices.DEVICE_MAKE, CTEDevices.DEVICE_Model,
CTERegistration.CREATED_ON, CTERegistration.CUSTOMER_INFO_ID, CTERegistration.DEVICE_MAKE, CTERegistration.DEVICE_Model
FROM CTEDevices INNER JOIN CTERegistration ON (CTEDevices.CUSTOMER_INFO_ID = CTERegistration.CUSTOMER_INFO_ID AND (CTEDevices.CREATED_ON = CTERegistration.CREATED_ON));
Individual qeueries were running successfully but when going to run as combined one getting the following error:
ORA-00932: inconsistent datatypes: expected DATE got NUMBER
Please help.
Thanks
Culprit is the 2nd CTE:
CTERegistration (CREATED_ON, CUSTOMER_INFO_ID, DEVICE_MAKE, DEVICE_Model) AS
( 1st 2nd
SELECT
CI.Customer_Info_Id, 1st
Trunc(CI.created_on), 2nd
'CI.DEVICE_MAKE', ...
The 1st column is supposed to be CREATED_ON (which is, apparently, DATE datatype value), while the 2nd column is then CUSTOMER_INFO_ID. Your query has it just the opposite, so - fix it:
CTERegistration (CREATED_ON, CUSTOMER_INFO_ID, DEVICE_MAKE, DEVICE_Model) AS
(
SELECT
Trunc(CI.created_on),
CI.Customer_Info_Id,
'CI.DEVICE_MAKE', ...
If you wonder why separate queries work, well - no reason why not. Oracle doesn't care how you named columns, but you can't join them any way you want.

SQL query for Oracle

I have 2 tables in oracle . users and profile table.
i am running following query to get results
SELECT fu.user_name ,papf.SSN
FROM apps.fnd_user fu, apps.per_all_people_f papf
WHERE fu.employee_id = papf.person_id
AND (TO_CHAR(papf.EFFECTIVE_END_DATE) IS NULL
OR papf.EFFECTIVE_END_DATE > SYSDATE )
Thing is that ,
Profile table has multiple records for SSN.
So this query is returning dupes for SSN.
I just want to get one distinct record for SSN.
for eg result is like
ABC 123
ABC 123
How do i just display unquie values for SSN
Like
ABC 123
U tried distinct but did not work
Any suggestions ?
Proper use of Distinct for your case...
SELECT Distinct fu.user_name , papf.SSN
FROM apps.fnd_user fu
, apps.per_all_people_f papf
WHERE fu.employee_id = papf.person_id
AND (TO_CHAR(papf.EFFECTIVE_END_DATE) IS NULL
OR papf.EFFECTIVE_END_DATE > SYSDATE )
Query using group by can be like below to have a single record:
SELECT fu.user_name ,
papf.SSN
FROM apps.fnd_user fu,
apps.per_all_people_f papf
WHERE fu.employee_id = papf.person_id
AND ( papf.EFFECTIVE_END_DATE IS NULL
OR papf.EFFECTIVE_END_DATE > trunc(SYSDATE) --assuming effective_end_date doesnot have timestamp with it.
)
group by fu.user_name,
papf.SSN ;

query with max and second factor [duplicate]

I have:
TABLE MESSAGES
message_id | conversation_id | from_user | timestamp | message
I want:
1. SELECT * WHERE from_user <> id
2. GROUP BY conversation_id
3. SELECT in every group row with MAX(timestamp) **(if there are two same timestamps in a group use second factor as highest message_id)** !!!
4. then results SORT BY timestamp
to have result:
2|145|xxx|10000|message
6|1743|yyy|999|message
7|14|bbb|899|message
with eliminated
1|145|xxx|10000|message <- has same timestamp(10000) as message(2) belongs to the same conversation(145) but message id is lowest
5|1743|me|1200|message <- has message_from == me
example group with same timestamp
i want from this group row 3 but i get row 2 from query
SELECT max(message_timestamp), message_id, message_text, message_conversationId
FROM MESSAGES
WHERE message_from <> 'me'
GROUP BY message_conversationId
ORDER by message_Timestamp DESC
what is on my mind to do union from message_id & timestamp and then get max???
Your query is based on non-standard use of GROUP BY (I think SQLite allows that only for compatibility with MySQL) and I'm not at all sure that it will produce determinate results all the time.
Plus it uses MAX() on concatenated columns. Unless you somehow ensure that the two (concatenated) columns have fixed widths, the results will not be accurate for that reason as well.
I would write the query like this:
SELECT
m.message_timestamp,
m.message_id,
m.message_text,
m.message_conversationId
FROM
( SELECT message_conversationId -- for every conversation
FROM messages as m
WHERE message_from <> 'me'
GROUP BY message_conversationId
) AS mc
JOIN
messages AS m -- join to the messages
ON m.message_id =
( SELECT mi.message_id -- and find one message id
FROM messages AS mi
WHERE mi.message_conversationId -- for that conversation
= mc.message_conversationId
AND mi.message_from <> 'me'
ORDER BY mi.message_timestamp DESC, -- according to the
mi.message_id DESC -- specified order
LIMIT 1 -- (this is the one part)
) ;
Try below sql to achieve your purpose by group by twice.
select m.*
from
Messages m
-- 3. and then joining to get wanted output columns
inner join
(
--2. then selecting from this max timestamp - and removing duplicates
select conversation_id, max(timestamp), message_id
from
(
-- 1. first select max message_id in remainings after the removal of duplicates from mix of cv_id & timestamp
select conversation_id, timestamp, max(message_id) message_id
from Messages
where message <> 'me'
group by conversation_id, timestamp
) max_mid
group by conversation_id
) max_mid_ts on max_mid_ts.message_id = m.message_id
order by m.message_id;
http://goo.gl/MyZjyU
ok it was more simple than I thought:
basically to change select from:
max(message_timestamp)
to:
max(message_timestamp || message_id)
or max(message_timestamp + message_id)
so it will search for max on concatenation of timestamp and message_id
ps. after a digging - it's working only if message id is growing with timestamp ( order of insertion is preserved )
edit:
edit2 :
so why it works ?
SELECT max(message_timestamp+message_id), message_timestamp, message_id, message_conversationId, message_from,message_text
FROM MESSAGES
WHERE message_conversationId = 1521521
AND message_from <> 'me'
ORDER by message_Timestamp DESC

Avoid repetition of subquery

I have a table messages that contains a column message_internaldate. Now I'd like to count the messages within certain time periods (each hour of a day) over several months. I could manage to get the sum of messages per hour by having lots of subqueries (24) but I hope that there is a more brainy way to do that. The subqueries are similar except that the time period changes. Any suggestions?
e.g. for the first two hours
SELECT T1, T2 FROM
(
SELECT sum(T1c) as T1 FROM
(
SELECT strftime('%H:%M',message_internaldate) AS T1s ,count(*) as T1c FROM messages WHERE
message_internaldate BETWEEN '2005-01-01 00:00:00' AND '2012-12-31 00:00:00'
AND strftime('%H:%M',message_internaldate) BETWEEN '01:00'AND '01:59'
GROUP BY strftime('%H:%M',message_internaldate)
)
)
,
(
SELECT sum(T2c) as T2 FROM
(
SELECT strftime('%H:%M',message_internaldate) AS T2s ,count(*) as T2c FROM messages WHERE
message_internaldate BETWEEN '2005-01-01 00:00:00' AND '2012-12-31 00:00:00'
AND strftime('%H:%M',message_internaldate) BETWEEN '02:00'AND '02:59'
GROUP BY strftime('%H:%M',message_internaldate)
)
)
...
Your problem is that you want to have the individual hours as columns.
To get them as rows, try a query like this:
SELECT strftime('%H', message_internaldate) AS hour,
strftime('%H:%M', message_internaldate) AS Ts,
COUNT(*) AS Tc
FROM messages
WHERE message_internaldate BETWEEN '2005-01-01 00:00:00' AND '2012-12-31 23:59:59'
GROUP BY 1, 2

Getting All the record of particular month - Building SQL Query

I need some help to build SQL Query. I have table having data like:
ID Date Name
1 1/1/2009 a
2 1/2/2009 b
3 1/3/2009 c
I need to get result something like...
1 1/1/2009 a
2 1/2/2009 b
3 1/3/2009 c
4 1/4/2009 Null
5 1/5/2009 Null
6 1/6/2009 Null
7 1/7/2009 Null
8 1/8/2009 Null
............................
............................
............................
30 1/30/2009 Null
31 1/31/2009 Null
I want query something like..
Select * from tbl **where month(Date)=1 AND year(Date)=2010**
Above is not completed query.
I need to get all the record of particular month, even if some date missing..
I guess there must be equi Join in the query, I am trying to build this query using Equi join
Thanks
BIG EDIT
Now understand the OPs question.
Use a common table expression and a left join to get this effect.
DECLARE #FirstDay DATETIME;
-- Set start time
SELECT #FirstDay = '2009-01-01';
WITH Days AS
(
SELECT #FirstDay as CalendarDay
UNION ALL
SELECT DATEADD(d, 1, CalendarDay) as CalendarDay
FROM Days
WHERE DATEADD(d, 1, CalendarDay) < DATEADD(m, 1, #FirstDay)
)
SELECT DATEPART(d,d.CalendarDay), **t.date should be (d.CalendarDay)**, t.Name FROM Days d
LEFT JOIN tbl t
ON
d.CalendarDay = t.Date
ORDER BY
d.CalendarDay;
Left this original answer at bottom
You need DATEPART, sir.
SELECT * FROM tbl WHERE DATEPART(m,Date) = 1
If you want to choose month and year, then you can use DATEPART twice or go for a range.
SELECT * FROM tbl WHERE DATEPART(m,Date) = 1 AND DATEPART(yyyy,Date) = 2009
Range :-
SELECT * FROM tbl WHERE Date >= '2009-01-01' AND Date < '2009-02-01'
See this link for more info on DATEPART.
http://msdn.microsoft.com/en-us/library/ms174420.aspx
You can use less or equal to.
Like so:
select * from tbl where date > '2009-01-01' and date < '2009-02-01'
However, it is unclear if you want month 1 from all years?
You can check more examples and functions on "Date and Time Functions" from MSDN
Create a temporary table containing all days of that certain month,
Do left outer join between that table and your data table on tempTable.month = #month.
now you have a big table with all days of the desired month and all the records matching the proper dates + empty records for those dates who have no data.
i hope that's what you want.

Resources