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')
Related
I’m trying to use a correlated subquery in my sql code and I can't wrap my head around what I'm doing wrong. A brief description about the code and what I'm trying to do:
The code consists of a big query (ALIASED AS A) which result set looks like a list of customer IDs, offer IDs and response status name ("SOLD","SELLING","IRRELEVANT","NO ANSWER" etc.) of each customer to each offer. The customers IDs and the responses in the result set are non-unique, since more than one offer can be made to each customer, and a customer can have different response for different offers.
The goal is to generate a list of distinct customer IDs and to mark each ID with 0 or 1 flag :
if the ID has AT LEAST ONE offer with status name is "SOLD" or "SELLING" the flag should be 1 otherwise 0. Since each customer has an array of different responses, what I'm trying to do is to check if "SOLD" or "SELLING" appears in this array for each customer ID, using correlated subquery in the case statement and aliasing the big underlying query named A with A1 this time:
select distinct
A.customer_ID,
case when 'SOLD' in (select distinct A1.response from A as A1
where A.customer_ID = A1.customer_ID) OR
'SELLING' in (select distinct A1.response from A as A1
where A.customer_ID = A1.customer_ID)
then 1 else 0 end as FLAG
FROM
(select …) A
What I get is a mistake alert saying there is no such object as A or A1.
Thanks in advance for the help!
You can use exists with cte :
with cte as (
<query here>
)
select c.*,
(case when exists (select 1
from cte c1
where c1.customer_ID = c.customer_ID and
c1.response in ('sold', 'selling')
)
then 1 else 0
end) as flag
from cte c;
You can also do aggregation :
select customer_id,
max(case when a.response in ('sold', 'selling') then 1 else 0 end) as flag
from < query here > a;
group by customer_id;
With statement as suggested by Yogesh is a good option. If you have any performance issues with "WITH" statement. you can create a volatile table and use columns from volatile table in your select statement .
create voltaile table as (select response from where response in ('SOLD','SELLING').
SELECT from customer table < and join voltaile table>.
The only disadvantge here is volatile tables cannot be accessed after you disconnect from session.
I have a view defined in SQL Server database and it has two columns A and B, both of which have the type of INT. I want to find out the relationship between these two, 1 to 1 or 1 to many or many to many. Is there a SQL statement I can use to find out?
For the relationship, it means for a given value of A, how many values of B maps to this value. If there is only one value, then it is 1 to 1 mapping.
You could use CTEs to generate COUNTs of how many distinct A values were associated with each B value and vice versa, then take the MAX of those values to determine if the relationship is 1 or many on each side. For example:
WITH CTEA AS (
SELECT COUNT(DISTINCT B) ac
FROM t
GROUP BY A
),
CTEB AS (
SELECT COUNT(DISTINCT A) bc
FROM t
GROUP BY B
)
SELECT CONCAT(
CASE WHEN MAX(bc) = 1 THEN '1' ELSE 'many' END,
' to ',
CASE WHEN MAX(ac) = 1 THEN '1' ELSE 'many' END
) AS [A to B]
FROM CTEA
CROSS JOIN CTEB
Note that any time a relationship is listed as 1, it may actually be many but just not showing that because of limited data in the table.
Demo on dbfiddle
Assuming you have no NULL values:
select (case when count(*) = count(distinct a) and
count(*) = count(distinct b)
then '1-1'
when count(*) = count(distinct a) or
count(*) = count(distinct b)
then '1-many'
else 'many-many'
end)
from t;
Note: This does not distinguish between 1-many for a-->b or b-->a.
You would use count and group by to get this information.
--This would give you count of values of b which map to every values of a. If there is at least one row with a count give you a value greater than 1 it means the mapping between a and b is one to many.
select a,count( distinct b)
from table
group by a
If all of the rows have the values equal to one for all of the elements in a then the mapping is one-one
A caveat , null in b would be ignored in count expressions. ie because null and another null is not equivalent
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;
I have to determine how many rows are active from each Table. Then return the answers in one query AND put the results in a Table Variable.
a. Path
b. Course
c. Section
d. Event
I was able to determine the active rows with the following query:
SELECT * FROM [dbo].[ADF_Path]
WHERE PathActive is NULL
SELECT * FROM [dbo].[ADF_Course]
WHERE CourseActive = '1'OR
CourseActive = 'y'
SELECT * FROM [dbo].[ADF_Event]
WHERE EventActive = 'y'
Is it POSSIBLE to join these tables in order to arrive at the same conclusion
OR
How do I determine the active rows in 1 query?
Placing the query in a Variable Table is not a problem. I just need to know
how to formulate the query. (See Tables below)
Thank You
do you want something like?:
SELECT count(*) as cnt FROM [dbo].[ADF_Path] WHERE PathActive is NULL
union all
SELECT count(*) FROM [dbo].[ADF_Course] WHERE CourseActive = '1' OR CourseActive = 'y'
union all
SELECT count(*) FROM [dbo].[ADF_Event] WHERE EventActive = 'y'
you can also add column to distinguish between different counts, or summarize them like:
select sum(cnt) from ( <union query from above> ) as t
I have one table things full of items listed by ItemID. Given an ItemID, I need to get the record with the ItemID and all other items with the same name.
In the sample data below, given the ItemID of 1, I need to select all records with the same name (in this case, "poptarts") as ItemID 1, including the record with ItemID 1.
ItemID = 1 name = poptarts
ItemID = 7 name = poptarts
ItemID = 8 name = cheddar
ItemID = 323 name = poptarts
select a.ItemID, a.name from things where a.ItemID = '1'
UNION
select b.ItemID, b.name from things where b.name = a.name
The SQL I've written above however does not pass a.name to the second select. Is there any way to pass the first name value to the second select? I would like for the statement to return itemid = 1 as the first row and 7 and 323 as the other rows.
UNION is only really used to concatenate two distinct sets. Based on your example, you could probably do something like this:
SELECT a.ItemID, a.Name
FROM things a
WHERE name IN (SELECT name FROM things WHERE itemID = 1)
There are lots of ways to write this kind of query and will depend on which flavor of SQL you're using but this should be more or less universal.
select
a.itemID,
a.name
from
things a
where a.name in (
select name
from things b
where b.itemID = '1'
)
SELECT this.name, this.id, that.id
FROM thing this
LEFT JOIN thing that ON that.name=this.name AND that.id <> this.id
WHERE this.id = 1
;
NOTE: this also selects the this-rows that have no twin records; in that case the that.id will be NULL. If you want to suppress the records without twin-records, remove the LEFT.
UPDATE: added the id <> id clause to suppres the obvious match.
If you really only have one table, no need to bring it in twice, UNION, or anything fancy like htat.
SELECT
name
FROM
a --assuming this is your only table
GROUP BY
itemID, name
HAVING
itemID = '1'