T-SQL sub query - sql-server

I was trying to build one query in SQL but was not being able to and need someone's help, the requirement is as below,
Extract only the accounts where there is no after_image = '0199d' present or if its presents the audit_Date should be < 20170701. Also unique accounts should be extracted. Please suggest

select acct, max(audit_date)from yourtable a
where not exists (select 1 from yourtable b where a.acct=b.acct and b.after_image = '0199d'
and b.audit_Date >= '20170701')
group by acct

Related

SQL Server - Distinct

This is my table:
I want to know which names exist more than once with the source "comp" and the source "manual".
So in this case I want the output to be: host3 zyx (name and group)
because the name host3 exists more than once and it has the source manual and the source comp.
I've tried this (SQL Server):
SELECT name, group
FROM table
GROUP BY name
HAVING (COUNT(name) > 1) and ????
As I understand you want something like
SELECT name, max([group]) -- or STRING_AGG([group],',')
FROM table
WHERE source in ('comp','manual')
GROUP BY name
HAVING COUNT(DISTINCT source) > 1
or you have to group by (in most sql dialects) group, too
SELECT name, [group]
FROM table
WHERE source in ('comp','manual')
GROUP BY name, [group]
HAVING COUNT(DISTINCT source) > 1
I understand correctly, you can try to use condition aggregate function in HAVING COUNT with condition
We can use condition for WHERE to improve our performance if source creates a correct index.
SELECT name,[group]
FROM [table]
WHERE source in ('comp','manual')
GROUP BY name,[group]
HAVING COUNT(DISTINCT CASE WHEN source = 'manual' THEN source END) = 1
AND COUNT(DISTINCT CASE WHEN source = 'comp' THEN source END) = 1
Another way to think about it is to calculate the counts inside a CTE and then filter:
; -- see sqlblog.org/cte
WITH cte AS
(
SELECT name,
[group],
SourceCount = COUNT(DISTINCT source)
FROM dbo.tablename
WHERE source IN ('comp', 'manual')
GROUP BY name, [group]
)
SELECT name, [group]
FROM cte
WHERE SourceCount = 2;
Example db<>fiddle
If you think CTEs are icky, or don't like that I write them defensively, you can also use a subquery:
SELECT name, [group] FROM
(
SELECT name, [group],
SourceCount = COUNT(DISTINCT source)
FROM dbo.tablename
WHERE source IN ('comp', 'manual')
GROUP BY name, [group]
) AS q WHERE SourceCount = 2;
Example db<>fiddle
And again, the point is to provide another way to think about it, especially for new learners, not to use the fewest number of characters possible, or to appease people who can only think about queries in one way and that theirs is the only "good" or "right" way to solve a problem or teach others.
These two and the accepted answer all have identical performance, down to seven decimal places of subtree cost. Just because you don't like the look of my Ford Taurus doesn't mean it's a bad way for me to get downtown (or an unacceptable way to give someone a ride). I blogged about this here.

Find customer who placed order every month and who did not place order every month

I am looking for a query than can list the customers
who placed order every month form the following table? A: 123
who did not place an order every month? A:everyone except 123
I am not proficient in such codes and I tried build sub-queries and cte's but I am not able to build my logic. I tried the following but not able to progress.
; with cte as(
SELECT customer_id,DATEPART(MONTH,Customer) as month,count(units) as no_of_order
from dwqc.dbo.orders
group by customer_id,DATEPART(MONTH,Customer))
select * from cte
Could someone please help me out with this? Thanks!
SELECT customer_id
from dwqc.dbo.orders
group by customer_id
having count(distinct DATEPART(MONTH,Customer))
= (select count(distinct DATEPART(MONTH,Customer)) from dwqc.dbo.orders)
Thanks #Nick.McDermaid

How to find the count of users who follow the same order sequence?

I'm having trouble thinking this through. I have about 3 million rows with columns: userID, Channel the user last came in from before purchase, and their order sequence. I would like to find a way to the count of users that follow the same order sequences based on the channel. Is there a certain function that can help me accomplish this?
Ex. TPA --> TPA --> Email
how many people follow this sequence?
You can get the sequences using string_agg():
select path, count(*) as num_users
from (select user_id,
string_agg(channel, '-->') within group (order by sequence) as path
from t
group b user_id
) u
group by path
order by num_users desc;
string_agg() is a relatively new function. In older versions of SQL Server, you would probably use XML functions.
If you just need to count them, you could first group them, and then perform a count. In fact, once grouped you can do whatever you like...
WITH dte as (
SELECT distinct
userid,
(
SELECT Channel+'>'
FROM MyTable t2
WHERE t2.userid= t.userid
FOR XML PATH('')
) Concatenated
FROM MyTable t
)
SELECT whatever
FROM dte
Hope this works out for you. :)

T-SQL: GROUP BY, but while keeping a non-grouped column (or re-joining it)?

I'm on SQL Server 2008, and having trouble querying an audit table the way I want to.
The table shows every time a new ID comes in, as well as every time an IDs Type changes
Record # ID Type Date
1 ae08k M 2017-01-02:12:03
2 liei0 A 2017-01-02:12:04
3 ae08k C 2017-01-02:13:05
4 we808 A 2017-01-03:20:05
I'd kinda like to produce a snapshot of the status for each ID, at a certain date. My thought was something like this:
SELECT
ID
,max(date) AS Max
FROM
Table
WHERE
Date < 'whatever-my-cutoff-date-is-here'
GROUP BY
ID
But that loses the Type column. If I add in the type column to my GROUP BY, then I'd get get duplicate rows per ID naturally, for all the types it had before the date.
So I was thinking of running a second version of the table (via a common table expression), and left joining that in to get the Type.
On my query above, all I have to join to are the ID & Date. Somehow if the dates are too close together, I end up with duplicate results (like say above, ae08k would show up once for each Type). That or I'm just super confused.
Basically all I ever do in SQL are left joins, group bys, and common table expressions (to then left join). What am I missing that I'd need in this situation...?
Use row_number()
select *
from ( select *
, row_number() over (partition by id order by date desc) as rn
from table
WHERE Date < 'whatever-my-cutoff-date-is-here'
) tt
where tt.rn = 1
I'd kinda like know how many IDs are of each type, at a certain date.
Well, for that you use COUNT and GROUP BY on Type:
SELECT Type, COUNT(ID)
FROM Table
WHERE Date < 'whatever-your-cutoff-date-is-here'
GROUP BY Type
Basing on your comment under Zohar Peled answer you probably looking for something like this:
; with cte as (select distinct ID from Table where Date < '$param')
select [data].*, [data2].[count]
from cte
cross apply
( select top 1 *
from Table
where Table.ID = cte.ID
and Table.Date < '$param'
order by Table.Date desc
) as [data]
cross apply
( select count(1) as [count]
from Table
where Table.ID = cte.ID
and Table.Date < '$param'
) as [data2]

How to calculate the days between 2 dates from 2 successive IDs

I need some help to create a new column in a database in SQL Server 2008.
I have the following data table
Please have a look at a snapshot of my table
Table
In the blank column I would like to put the difference between the current status date and the next status' date. And for the last ID_Status for each ID_Ticket I would like to have the difference between now date and it's date !
I hope that you got an idea about my problem.
Please share if you have any ideas about how to do .
Many thanks
kind regards
You didn't specify your RDBMS, so I'll post an answer for both since they are almost identical :
SQL-Server :
SELECT ss.id_ticket,ss.id_status,ss.date_status,
DATEDIFF(day,ss.date_status,ss.coalesce(ss.next_date,GETDATE())) as diffStatus
FROM (
SELECT t.*,
(SELECT TOP 1 s.date_status FROM YourTable s
WHERE t.id_ticket = s.id_ticket and s.date_status > t.date_status
ORDER BY s.date_status ASC) as next_date)
FROM YourTable t) ss
MySQL :
SELECT ss.id_ticket,ss.id_status,ss.date_status,
DATEDIFF(ss.date_status,ss.coalesce(ss.next_date,now())) as diffStatus
FROM (
SELECT t.*,
(SELECT s.date_status FROM YourTable s
WHERE t.id_ticket = s.id_ticket and s.date_status > t.date_status
ORDER BY s.date_status ASC limit 1) as next_date)
FROM YourTable t) ss
This basically first use a correlated sub query to bring the next date using limit/top , and then wrap it with another select to calculate the difference between them using DATEDIFF().
Basically it can be done without the wrapping query, but it won't be readable since the correlated query will be inside the DATEDIFF() function, so I prefer this way.

Resources