SQL Server 2008 SELECT - sql

I have a table with lots of columns. One of the columns is AppointmentNo, and this column can be either 1 or 2 (basically it is either a first appointment or followup).
Some of the columns include
tblAppoints:
ClientID
ClientFirstName
ClientLastName
ClientAddress
ClientAppointmentNo
I'm trying to select clientID's from this table, however, I don't want to see any clients where the ClientAppointmentNo = 2. So only show clients that have AppointmentNo = 1, no clients with ClientAppointmentNo = 2.

Here is one method, using aggregation:
select a.clientId
from tblAppoints a
group by a.clientId
having max(ClientAppointmentNo) = 1;
If you want to see the appointment details, then one method uses window functions:
select a.*
from (select a.*,
max(ClientAppointmentNo) over (partition by a.clientId) as maxcan
from tblAppoints a
) a
where maxcan = 1;

Related

SQL to find "clients" with a specific missing attribute

Is there a way to use a SQL statement on 1 table in which the result is the clients who do NOT have one specific attribute?
The table exists of multiple columns. One of them is Clientand another one is Product. One client can have several different records with different product-values.
Every client should at least have one specific product (for example X), next to a lot of different other values of product he can have. I would like to use a statement which returns all clients who don't have product X.
There are several ways:
Using NOT EXISTS as following:
SELECT client
FROM yourTable T
WHERE NOT EXISTS
(SELECT 1 FROM yourTable TIN
WHERE TIN.product = 'product X'
AND T.CLIENT = TIN.CLIENT
);
Using NOT IN
SELECT client
FROM yourTable T
WHERE client not in
(SELECT tin.client FROM yourTable TIN
WHERE TIN.product = 'product X'
);
Using group by, as shown in the other answers
select client
from yourTable
group by client
HAVING COUNT(CASE WHEN product = 'product X' THEN 1 END) = 0;
Aggregation is one simple option:
SELECT client
FROM yourTable
GROUP BY client
HAVING COUNT(CASE WHEN product = 'product X' THEN 1 END) = 0;
This works by keeping a count, for each client, of each record which matches product X. Assuming a client never has this product, the count would be zero.
Try it with NOT IN.
SELECT *
FROM table1
WHERE product NOT IN ('X')
SELECT [Clients] FROM [tablename] WHERE Product != 'X'
Use subquery to get all records which have X and then in the main query get all records which are not in this subset:
SELECT DISTINCT table_name.client FROM table_name WHERE table_name.client NOT IN (SELECT DISTINCT table_name.client FROM table_name WHERE table_name.product = 'X')

Get top 1 row for every ID

There is a few posts about it but i can't make it work...
I just want to select just one row per ID, something like row_number() over Partition in oracle but in access.
ty
SELECT a.*
FROM DATA as a
WHERE a.a_sku = (SELECT top 1 b.a_sku
FROM DATA as b
WHERE a.a_sku = b.a_sku)
but i get the same table Data out of it
Sample of table DATA
https://ibb.co/X4492fY
You should try below query -
SELECT a.*
FROM DATA as a
WHERE a.Active = (SELECT b.Active
FROM DATA as b
WHERE a.a_sku = b.a_sku
AND a.Active < b.Active)
If you don't care which record within each group of records with a matching a_sku values is returned, you can use the First or Last functions, e.g.:
select t.a_sku, first(t.field2), first(t.field3), ..., first(t.fieldN)
from data t
group by t.a_sku

SQL Server: Each GROUP BY expression must contain at least one column that is not an outer reference

scenario 1:
I have two tables INFUSION_APP_APPOINTMENT,INFUSION_APP_NURSE_NOTES where
INFUSION_APP_NURSE_NOTES.APPOINTMENT_ID=INFUSION_APP_APPOINTMENT.ID and i want to find out the INFUSION_APP_NURSE_NOTES.ID's where INFUSION_APP_NURSE_NOTES.APPOINTMENT_ID is same.
for eg. if the INFUSION_APP_NURSE_NOTES.APPOINTMENT_ID = 1 and INFUSION_APP_NURSE_NOTES.ID is 12,15,78, then i want to display all the
INFUSION_APP_NURSE_NOTES.ID's where INFUSION_APP_NURSE_NOTES.APPOINTMENT_ID =1.
i use below script
SELECT INFUSION_APP_NURSE_NOTES.APPOINTMENT_ID,INFUSION_APP_NURSE_NOTES.ID
FROM INFUSION_APP_NURSE_NOTES
GROUP BY INFUSION_APP_NURSE_NOTES.APPOINTMENT_ID,INFUSION_APP_NURSE_NOTES.ID
HAVING COUNT(INFUSION_APP_NURSE_NOTES.APPOINTMENT_ID)>1
but it does not gives me any records.
scenario 2:
I am running below script with the intention to get the duplicate records with different INFUSION_APP_NURSE_NOTES.ID's but same INFUSION_APP_NURSE_NOTES.APPOINTMENT_ID.
SELECT INFUSION_APP_NURSE_NOTES.ID,INFUSION_APP_NURSE_NOTES.APPOINTMENT_ID,INFUSION_APP_NURSE_NOTES.TYPE
FROM INFUSION_APP_NURSE_NOTES
WHERE
EXISTS (
SELECT 1 FROM INFUSION_APP_APPOINTMENT
WHERE
INFUSION_APP_NURSE_NOTES.ENABLE=1
AND INFUSION_APP_NURSE_NOTES.APPOINTMENT_ID=INFUSION_APP_APPOINTMENT.ID
GROUP BY INFUSION_APP_NURSE_NOTES.ID
HAVING COUNT(INFUSION_APP_NURSE_NOTES.APPOINTMENT_ID)>1
)
ORDER BY INFUSION_APP_NURSE_NOTES.APPOINTMENT_ID;
but getting below error
SQL Error(164): Each GROUP BY expression must contain at least one
column that is not an outer reference
how to solve it?
i want the only row which has common APPOINTMENT_ID but different n
The question is unclear. Finding duplicates is typically performed using ranking functions like ROW_NUMBER(). This query :
SELECT *,ROW_NUMBER(PARTITION BY APPOINTMENT_ID ORDER BYID) as RN
FROM INFUSION_APP_NURSE_NOTES
WHERE
ENABLE=1
Will rank notes for the same appointment by ID and return 1, 2, 3 etc starting from the earliest note. ORDER BY ID DESC would return 1 for the latest note.
This can be used in a subquery or CTE to find the first, last or or duplicate records, eg :
with notes as (
SELECT *,ROW_NUMBER(PARTITION BY APPOINTMENT_ID ORDER BYID) as RN
FROM INFUSION_APP_NURSE_NOTES
WHERE
ENABLE=1
)
select *
from notes
where RN=1
Will return the first note per appointment while :
where RN>1
Will return only duplicates.
The question doesn't say what should be done with the duplicates though.
If the question is how to return all notes from appointments with multiple notes, a subquery can be used to return the APPOINTMENT_IDs that have more than one note. There's no need to include the INFUSION_APP_APPOINTMENT table though :
SELECT *
FROM INFUSION_APP_NURSE_NOTES
where
ENABLE=1 AND
APPOINTMENT_ID IN ( SELECT APPOINTMENT_ID
FROM INFUSION_APP_NURSE_NOTES
WHERE
ENABLE=1
group by APPOINTMENT_ID
having count(*)>1)
Try this
SELECT INFUSION_APP_NURSE_NOTES.ID,INFUSION_APP_NURSE_NOTES.APPOINTMENT_ID,INFUSION_APP_NURSE_NOTES.TYPE
FROM INFUSION_APP_NURSE_NOTES
WHERE
EXISTS (
SELECT COUNT(B.APPOINTMENT_ID), B.ID
FROM INFUSION_APP_APPOINTMENT A
INNER JOIN INFUSION_APP_NURSE_NOTES B ON B.APPOINTMENT_ID = A.ID
WHERE
B.ENABLE=1
GROUP BY B.ID
HAVING COUNT(B.APPOINTMENT_ID)>1
)
ORDER BY INFUSION_APP_NURSE_NOTES.APPOINTMENT_ID;

Find records in SQL Server 2008 R2

Please find below image for make understanding my issues. I have a table as shown below picture. I need to get only highlighted (yellow) records. What is the best method to find these records?
In SQL Server 2012+, you can use the lead() and lag() functions. However, this is not available in SQL Server 2008. Here is a method using outer apply:
select t.*
from t outer apply
(select top 1 tprev.*
from t tprev
on tprev.time < t.time
order by tprev.time desc
) tprev outer apply
(select top 1 tnext.*
from t tnext
on tnext.time > t.time
order by tnext.time asc
)
where (t.cardtype = 1 and tnext.cardtype = 2) or
(t.cardtype = 2 and tprev.cardtype = 1);
With your sample data, it would also be possible to use self joins on the id column. This seems unsafe, though, because there could be gaps in that columns values.
Havent tried this, but I think it should work. First, make a view of the table in your question, with the rownumber included as one column:
CREATE VIEW v AS
SELECT
ROW_NUMBER() OVER(ORDER BY id) AS rownum,
id,
time,
card,
card_type
FROM table
Then, you can get all the rows of type 1 followed by a row of type 2 like this:
SELECT
a.id,
-- And so on...
FROM v AS a
JOIN v AS b ON b.rownum = a.rownum + 1
WHERE a.card_type = 1 AND b.card_type = 2
And all the rows of type 2 preceded by a row of type 1 like this:
SELECT
b.id,
-- And so on...
FROM v AS b
JOIN v AS a ON b.rownum = a.rownum + 1
WHERE a.card_type = 1 AND b.card_type = 2
To get them both in the same set of results, you can just use UNION ALL. Technically, you don't need the view. You could use nested selects instead, but since you will need to query the table four times it might be nice to have it as a view.
Also, if the ID is continous (it goes 1, 2, 3 without any gaps), you don't need the rownum and can just use the ID instead.
here is a code you can run in sql server
select * from Table_name where id in (1,2,6,7,195,160,164,165)

Selecting Random Record for each User returned in the results

I have seen several ways of selecting random records from a table using several methods. However, my need I am sure is here, I just cannot find it. I have a query using several tables. What my end goal is is to have one random record for each user returned.
In my result set, I get users and the work items they have. What I need is to only return one random work item per user. This is where I am getting stuck. ANy assistance would be greatly appreciated.
Here is my code. What I need is 1 random C.credentilaing_k per user.
select
U.FULLNAME as 'Chg_By',
CONVERT(DATE,AL.AUDITDATETIME) as 'DE_Date',
P.ID,
P.LONGNAME,
CONVERT(DATE,P.DATEOFBIRTH) as 'DOB',
C.CREDENTIALING_K,
C.entity_k,
R.DESCRIPTION as 'CVI_TYPE',
CG.GROUPDESCRIPTION,
C.APPLICATION_RECEIVED,
R1.DESCRIPTION as 'Cur_STATUS',
CONVERT(DATE,C.USERDEF_D3) as 'MSO_DUE_DT'
from
VisualCACTUS.AUDITLOG AL
JOIN VisualCACTUS.USERS U
on U.user_k = AL.USER_K
join VisualCACTUS.CREDENTIALING C
JOIN VisualCACTUS.PROVIDERS P
on P.provider_k = C.PROVIDER_K
JOIN visualcactus.CREDENTIALINGGROUP CG
on CG.CREDENTIALINGGROUP_K = C.CREDENTIALINGGROUP_K
JOIN VisualCACTUS.REFTABLE R
on R.reftable_k = C.TYPE_RTK
JOIN VisualCACTUS.REFTABLE R1
ON R1.REFTABLE_K = C.CREDENTIALINGSTATUS_RTK
on C.CREDENTIALING_K = AL.FILE_PRIMARYKEY
where
AUDITLOG_K in (select AUDITLOG_K from VisualCACTUS.AUDITLOG_RECORDLEVEL where TABLE_NAME = 'CREDENTIALING '
and
AUDITLOG_RECORDLEVEL_K in (SELECT AUDITLOG_RECORDLEVEL_K from VisualCACTUS.AUDITLOG_FIELDLEVEL where NEWVALUE_SHORT = 'D2LC0YSXXW'))
and
CONVERT(DATE, AUDITDATETIME) = DATEADD(day, -1, convert(date, GETDATE()))
I think you need something like this (in T-SQL):
SELECT *
FROM (
SELECT *,
ROW_NUMBER() OVER (PARTITION BY UserId ORDER BY NEWID()) rn
FROM yourTable) dt
WHERE
rn = 1;
What you want is to get a random record for a user if the user is having multiple records. We may do something as below (In Teradata):
select
*
from tablename
where
qualify row_number() (over partition by id order by column) = 1;
Here:
partition by - can have multiple columns seperated by comma incase you want to segregate your data based on few columns.
order by - can be given just to arrange the data in that segment based on your preference, it can be on date or anything as per your data.
=1 - signifies take the first among them.