I have this
ID
Product
001
A
001
B
001
C
002
A
002
A
002
D
003
G
003
D
003
C
004
G
004
D
004
R
and I wand ID list if they don't have product C...so:
002
You can apply the set difference between all ids and all ids with a "c" with the standard way of doing it: using the NOT IN operator in the WHERE clause.
SELECT DISTINCT ID
FROM tab
WHERE id NOT IN (SELECT ID FROM tab WHERE Product = 'C')
Consider below query:
SELECT DISTINCT ID FROM (
SELECT *, COUNTIF(product = 'C') OVER (PARTITION BY ID) AS cnt_C
FROM sample_table
) WHERE cnt_C = 0
output:
There are multiple ways of doing this, but I think a very readable way is to use NOT EXISTS.
SELECT DISTINCT id
FROM mytable t1
WHERE NOT EXISTS (SELECT 1 FROM mytable t2 WHERE t2.id = t1.id AND t2.Product = 'C')
The WHERE clause checks that there is no row with product C and the same id. The DISTINCT ensures you don't get multiples of the same id returned.
I am not sure but I think you just need a normal where
SELECT * FROM table_name WHERE product != product_name
*insert the table name in the place of Table_name and product name in the place of product_name
select distinct
id
from
your_table_name
where
product <> 'C';
This will return you list of ID's that don't have product C
Related
I need some quick help on SQL. This is basic for most I am sure.
I want to select orderId in both tables merged that satisfies status = 1.
Please find example of the two table tb1 and tb2 here:
tb1
orderId status
---------------
001 0
003 1
005 1
007 1
...
tb2
orderId status
----------------
002 1
008 1
004 0
Use this query:
SELECT
tb1.OrderId,
tb1.Status
FROM
tb1
WHERE
tb1.status = 1
UNION
SELECT
tb2.OrderId,
tb2.Status
FROM
tb2
WHERE
tb2.status = 1;
You can use UNION ALL.
Your query would be:
SELECT *
FROM (
SELECT *
FROM tb1
UNION ALL
SELECT *
FROM tb2
) a
WHERE STATUS = 1
I have two tables like this:
Table1
ObjectName
ObjectId
Status
Name 1
001
OK
Name 2
002
OK
Name 3
003
Wait
Name 4
004
Wait
Table2
ObjectId
ObjectColor
001
Red
001
Blue
002
Magenta
002
Cyan
003
Blue
003
Green
004
Orange
004
Cyan
Now, I want to query ObjectName of any item with status OK in Table1 and without the color blue in Table2.
The nearest I can come is this:
SELECT
Table1.ObjectName
FROM
Table1
LEFT JOIN Table2 ON Table2.ObjectId = Table1.ObjectId
WHERE
Table1.Status = 'OK'
AND Table2.ObjectColor <> 'Blue'
This results in:
ObjectName
Name 1
Name 2
Name 2
I understand why this doesn't work. But what would be the correct approach?
I expect to only get one instance of Name 2 from this query.
Thanks!
Why join at all? You want data from table1, so select from table1. You want to exclude certain rows, which is why you have a WHERE clause. One restriction is Status = 'OK', the other is that NOT EXISTS 'Blue' for the object in table2.
select objectname
from table1
where status = 'OK'
and not exists
(
select null
from table2
where table2.objectid = table1.objectid
and table2.objectcolor = 'Blue'
);
As there are no nulls involved, you can do the same with the simpler NOT IN:
select objectname
from table1
where status = 'OK'
and objectid not in (select objectid from table2 where objectcolor = 'Blue');
You can use distinct if you just want the unique ObjectName
SELECT
Table1.ObjectName
FROM
Table1
WHERE
Table1.Status = 'OK'
and not exists
(select 1 from Table2 where ObjectColor = 'Blue' and table2.objectid=table1.objectid)
SELECT
Table1.ObjectName
FROM
Table1
JOIN
(
SELECT ObjectId FROM TABLE2 WHERE ObjectColor<>'BLUE'
)X ON Table1.ObjectId=X.OBJECTID
WHERE Table1.Status = 'OK'
You can use below query
At first I have selected the IDs from Table2 whose not have any entry belong to BLUE (SubQuery). After that I just join this result with Table1
SELECT * FROM Table1
Inner Join
(
SELECT Objectid from Table2
group By Objectid
Having SUM(Case when ObjectColor ='Blue' Then 1 else 0 end)=0
) t2
on Table1.Objectid=t2.Objectid
And Table1.status='OK'
I have table contain below data:
EMPCODE PAYCODE AMOUNT
------------------------
001 A 100
001 B 200
002 A 120
002 C 80
003 B 50
003 D 20
All PAYCODE in table at the moment are A, B, C, D.
However, other EMPCODE with other new PAYCODE such as E or F, might be added in later on.
EMPCODE 001 has PAYCODE A and B (he doesn't have PAYCODE C and D).
EMPCODE 002 has PAYCODE A and C (he doesn't have PAYCODE B and D).
EMPCODE 003 has PAYCODE B and D (he doesn't have PAYCODE A and C).
I want to create a simple stored procedure / SQL which can add the dummy records for each EMPCODE for PAYCODE which they don't own.
My expected result as below:
EMPCODE PAYCODE AMOUNT
------------------------
001 A 100
001 B 200
001 C 0
001 D 0
002 A 120
002 B 0
002 C 80
002 D 0
003 A 0
003 B 50
003 C 0
003 D 20
I can achieve that through coding but I need to do it via a stored procedure.
Is there any SQL stored procedure to achieve this?
Appreciate for the answer.
Use Join to get the result. SQLFiddle
SELECT C.EMPCODE, C.PAYCODE, ISNULL(D.AMOUNT, 0) AS AMOUNT FROM
(
SELECT * FROM
(SELECT EMPcode from Test GROUP BY EMPCODE) AS A,
(SELECT Paycode FROM Test GROUP BY PAYCODE) AS B
) AS C
LEFT JOIN Test AS D
ON C.EMPCODE=D.EMPCODE AND C.PAYCODE = D.PAYCODE
UPDATE:
1) To get the distinct EMPCODE from table
(SELECT EMPcode from Test GROUP BY EMPCODE) AS A
2) To get the distinct PAYCODE from table
(SELECT Paycode FROM Test GROUP BY PAYCODE) AS B
3) To get the all PAYCODE value for each Empcode.
SELECT * FROM
(SELECT EMPcode from Test GROUP BY EMPCODE) AS A,
(SELECT Paycode FROM Test GROUP BY PAYCODE) AS B
You can do this by generating all the combinations of empcode and paycode using a cross join in a sub-query that you then use as a derived table for a left join. To not insert already existing rows you should exclude them using a correlated not exists predicate. Written as a stored procedure it could look like this:
create proc insert_missing_values as
insert your_table (empcode, paycode, amount)
select distinct codes.empcode, codes.paycode, isnull(your_table.amount, 0) amount
from (
select t1.empcode, t2.paycode
from your_table t1, your_table t2
group by t1.empcode, t2.paycode
) codes
left join your_table on
codes.empcode = your_table.empcode
and
codes.paycode = your_table.paycode
where not exists (
select 1 from your_table
where codes.empcode = your_table.empcode and codes.paycode = your_table.paycode
)
Sample SQL Fiddle
Edit: as Sybase ASE doesn't support the explicit cross join you can use a unqualified implicit join with the same effect by doing from TableA, TableB which returns the Cartesian product of rows. See this Wikipedia article for an explanation.
I have a table like this
Table A:
Id Count
1 4
1 16
1 8
2 10
2 15
3 18
etc
Table B:
1 sample1.file
2 sample2.file
3 sample3.file
TABLE C:
Count fileNumber
16 1234
4 2345
15 3456
18 4567
and so on...
What I want is this
1 sample1.file 1234
2 sample2.file 3456
3 sample3.file 4567
To get the max value from table A I used
Select MAX (Count) from A where Id='1'
This works well but my problem is when combining data with another table.
When I join Table B and Table A, I need to get the MAX for all Ids and in my query I dont know what Id is.
This is my query
SELECT B.*,C.*
JOIN A on A.Id = B.ID
JOIN C on A.id = B.ID
WHERE (SELECT MAX(COUNT)
FROM A
WHERE Id = <what goes here????>)
To summarise, what I want is Values from Table B, FileNumber from Table c (where the count is Max for ID from table A).
UPDATE: COrrecting table C above. Looks like I need Table A.
I think this is the query you're looking for:
select b.*, c.filenumber from b
join (
select id, max(count) as count from a
group by id
) as NewA on b.id = NewA.id
join c on NewA.count = c.count
However, you should take into account that I don't get why for id=1 in tableA you choose the 16 to match against table C (which is the max) and for id=2 in tableA you choose the 10 to match against table C (which is the min). I assumed you meant the max in both cases.
Edit:
I see you've updated tableA data. The query results in this, given the previous data:
+----+---------------+------------+
| ID | FILENAME | FILENUMBER |
+----+---------------+------------+
| 1 | sample1.file | 1234 |
| 2 | sample2.file | 3456 |
| 3 | sample3.file | 4567 |
+----+---------------+------------+
Here is a working example
Using Mosty’s working example (renaming the keyword count to cnt for a column name), this is another approach:
with abc as (
select
a.id,
a.cnt,
rank() over (
partition by a.id
order by cnt desc
) as rk,
b.filename
from a join b on a.id = b.id
)
select
abc.id, abc.filename, c.filenumber
from abc join c
on c.cnt = abc.cnt
where rk = 1;
select
PreMax.ID,
B.FileName,
C2.FileNumber
from
( select C.id, max( C.count ) maxPerID
from TableC C
group by C.ID
order by C.ID ) PreMax
JOIN TableC C2
on PreMax.ID = C2.ID
AND PreMax.maxPerID = C2.Count
JOIN TableB B
on PreMax.ID = B.ID
Sorry for posting this question again. I rephrased my question a little bit.
I am trying to write a query to return rows from Table-A where multiple rows found in Table-B with STATUS = 1 for each CID column from Table-A.
So in this example CID 100 has two records found in Table-B and STATUS = 1. So I want to write a query to return this row from Table-A. I know this is a weird table design. Please help.
Here are the tables with sample data.
Table-A
-----------------------------------------
AID Name CID
---------------------------------------
10 test1 100
12 test1 100
13 test2 101
14 test2 101
15 test3 102
Table-B
------------------------------------
bID AID status
-----------------------------------
1 10 1
2 12 1
3 14 1
4 15 1
Try this query:
SELECT TableA.CID
FROM TableA
JOIN TableB ON TableA.AID = TableB.AID
WHERE TableB.status = 1
GROUP BY TableA.CID
HAVING COUNT(*) > 1
It returns 100 for your example data.
Something like this?
select aid,
status
from (select aid,
count(*) as cnt
from tableA
group by aid) as aggregated
left join tableB on tableB.aid = aggregated.aid
where aggregated.cnt > 1
If your using SQL:
WITH tableBView AS
(
SELECT AID AS xxxAID
FROM [Table-B]
WHERE status = 1
GROUP BY AID
HAVING COUNT(*) > 0
)
SELECT *
FROM [Table-A]
WHERE EXISTS (SELECT * FROM tableBView WHERE xxxAID = AID)
SELECT *
FROM Table-A a
WHERE a.CID IN
(
SELECT a.CID FROM Table-A a JOIN Table-B b USING (AID)
GROUP BY a.CID
WHERE b.status = 1
HAVING count(*) > 1
)
This is a very verbose way to do it.
Selects all columns from Table-A on rows where AID match between Table-A and Table-B and more than one row with the same CID exists in Table-A:
(Btw, I wouldn't use "-" in your table/column names. Use "_" instead.)
select
derived_table.AID,
derived_table.Name,
derived_table.CID
from
(select
table_A.AID,
table_A.Name,
table_A.CID,
count(table_A.CID) c
from
Table_A
inner join Table_B on (Table_A.AID = table_B.AID)
group by table_A.CID
) derived_table
where
c > 1