SQL select units with condition of another column - sql

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

Same column name from two tables satisfying two conditions

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

JOIN to get items without value in other table gives multiple results

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'

SQL Procedure (Sybase Advantage Database Server)

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.

Get the max value of a column from set of rows

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

SQL query help

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