How do I reference 2 aliases and compare them in WHERE clause? - sql

I have this
RECORD ITEMS ITEMSTOTAL
------------------------------------ ---------- ----------
ababababaa 0 1
ababababab 0 0
ababababac 0 1
ababababad 1 1
ababababae 0 2
but I need this output when ITEMS=ITEMSTOTAL
RECORD
------------------------------------
ababababab
ababababad
Currently I'm using this query for the first result, but I don't know how to get the second output, Maybe this sounds obvious but I can't find the answer :(
SELECT RECORD,
(SELECT COUNT(*) FROM TABLE1 WHERE SOMETHING=X) AS ITEMS,
(SELECT COUNT(*) FROM TABLE2 WHERE SOMETHING2=Y) AS ITEMSTOTAL
FROM RECORDS_TABLE
WHERE DELETED=0
--and ITEMS.count = ITEMSTOTAL.count <-- tried something like this but it doesn't work.

One option would be to use a subquery and apply the where criteria to the outer query.
select *
from (
your query here
) t
where items = itemstotal
I assume that isn't your actual query btw. where comes after from. Also, those count statements would return the same values.

Related

ORACLE fastest way to know if table contains rows

select 1 from MY_TABLE where ID=42 fetch first 1 rows only;
select 1 from MY_TABLE where ID=42 and rownum=1;
select case when exists (select 1 from MY_TABLE where ID=42) then 1 else 0 end from dual;
select count(1) from MY_TABLE where ID=42;
Here is 4 methods to check whether the table contains any rows. The last one is quite slow, but first 3 has approximatively the same time. What is the best practice (academically correct)?
Any other methods?
Unless throwing an exception is acceptable, in which case you will need to capture it, you will want to use a count with rownum = 1
select count(*) from my_table where id = 42 and rownum = 1;
In this case, the return value of 0 means there are no rows, 1 means there are 1 or more rows.
While this gives the same results as your select with case statement, it is much less complicated and easier to understand.

SQL Nested Select Statement

I have the following SQL Code which is not giving me my desired results.
SELECT
POLICIES.CLIENTS_ID,
POLICIES.CLIENTCODE,
COUNT(POLICIES.POLICIES_ID) as [Total Policies],
(
SELECT
COUNT(POLICIES.POLICIES_ID)
FROM
POLICIES
WHERE
POLICIES.COVCODE = 'AUT'
) as [Auto Policies]
FROM
POLICIES
LEFT JOIN CLIENTS
ON CLIENTS.CLIENTS_ID = POLICIES.CLIENTS_ID
WHERE
POLICIES.CNR IS NULL
GROUP BY
POLICIES.CLIENTS_ID,
POLICIES.CLIENTCODE
ORDER BY
POLICIES.CLIENTS_ID
I get a result like this:
ID CODE Total Auto
3 ABCDE1 1 999999
4 ABCDE2 1 999999
5 ABCDE3 2 999999
6 ABCDE4 2 999999
I would like for the last column to COUNT the total auto policies that exists for that clientid rather than all of the auto policies that exist. I believe I need a nested select statement that somehow groups all like results on the clientid, but it ends up returning more than 1 row and throws the error.
If I add:
GROUP BY
POLICIES.CLIENTS_ID
I get:
Subquery returned more than 1 value. This is not permitted when the....
Any help would be appreciated greatly!
Thank you
You can use a CASE statement to do this. Instead of your subquery in the SELECT clause use:
SUM(CASE WHEN POLICIES.COVCODE = 'AUT' THEN 1 ELSE 0 END) as [AUTO POLICIES]
As Martin Smith pointed out. If client_id has multiple client_codes then this will give you the count of records for each combination of client_id/client_code. If client_id is 1:1 with client_code then this will give you a count of records for each distinct client_id, which I suspect is the case from your example and question.
Unrelated: You have a LEFT JOIN to your Clients table, but you don't use your Clients table anywhere int he query. Consider removing it if you don't need to select or filter by any its fields, since it's just unused overhead.
What if you modify the inner query for getting count to something like
SUM(CASE WHEN POLICIES.COVCODE = 'AUT' THEN 1 ELSE 0 END) as [Auto Policies]

Update with results of another sql

With the sql below I count how many records I have in tableB for each code. The total field is assigned the result of the count and the code the code field of the record.
SELECT
"count" (*) as total,
tableB."code" as code
FROM
tableB
WHERE
tableB.code LIKE '%1'
GROUP BY
tableB.code
In tableA I have a sequence field and I update with the result of total (obtained in the previous sql) plus 1 Do this for each code.
I tried this and it did not work, can someone help me?
UPDATE tableA
SET tableA.sequence = (tableB.total + 1) where tableA."code" = tableB.code
FROM
(
SELECT
"count" (*) as total,
tableB."code" as code
FROM
tableB
WHERE
tableB.code LIKE '%1'
GROUP BY
tableB.code
)
I edited for my tables are as mostar believe facillita understanding of my need
tableA
code sequence
100 null
200 null
table B
code sequence
100 1
100 2
100 3
100 4
......
100 17
200 1
200 2
200 3
200 4
......
200 23
Need to update the sequence blank field in tableA with the number 18 to code = 100
Need to update the sequence blank field in tableA with the number 24 to code = 200
This assumes that code is unique in table_a:
with max_seq as (
select code,
max(sequence) + 1 as max_seq
from table_b
group by code
)
update table_a
set sequence = ms.max_seq
from max_seq ms
where table_a.code = ms.code;
SQLFiddle example: http://sqlfiddle.com/#!15/745a7/1
UPDATE tbl_a a
SET sequence = b.next_seq
FROM (
SELECT code, max(sequence) + 1 AS next_seq
FROM tbl_b
GROUP BY code
) b
WHERE a.code = b.code;
SQL Fiddle.
Only columns of the target table can be updated. It would not make sense to table-qualify those. Consequently, this is not allowed.
Every subquery must have a table alias for the derived table.
I would not use a CTE for a simple UPDATE like this. A subquery in the FROM clause is typically simpler and faster.
No point in double-quoting the aggregate function count(). No pint in double-quoting perfectly legal, lower case identifiers, either. No point in table-qualifying columns in a subquery on a single table in a plain SQL command (no harm either).
You don't need a WHERE condition, since you want to UPDATE all rows (as it seems). Note that only row with matching code are updated. Other rows in tbl_b remain untouched.
Basically you need to read the manual about UPDATE before you try any of this.

DB2 SQL filter query result by evaluating an ID which has two types of entries

After many attempts I have failed at this and hoping someone can help. The query returns every entry a user makes when items are made in the factory against and order number. For example
Order Number Entry type Quantity
3000 1 1000
3000 1 500
3000 2 300
3000 2 100
4000 2 1000
5000 1 1000
What I want to the query do is to return filter the results like this
If the order number has an entry type 1 and 2 return the row which is type 1 only
otherwise just return row whatever the type is for that order number.
So the above would end up:
Order Number Entry type Quantity
3000 1 1000
3000 1 500
4000 2 1000
5000 1 1000
Currently my query (DB2, in very basic terms looks like this ) and was correct until a change request came through!
Select * from bookings where type=1 or type=2
thanks!
select * from bookings
left outer join (
select order_number,
max(case when type=1 then 1 else 0 end) +
max(case when type=2 then 1 else 0 end) as type_1_and_2
from bookings
group by order_number
) has_1_and_2 on
type_1_and_2 = 2
has_1_and_2.order_number = bookings.order_number
where
bookings.type = 1 or
has_1_and_2.order_number is null
Find all the orders that have both type 1 and type 2, and then join it.
If the row matched the join, only return it if it is type 1
If the row did not match the join (has_type_2.order_number is null) return it no matter what the type is.
A "common table expression" [CTE] can often simplify your logic. You can think of it as a way to break a complex problem into conceptual steps. In the example below, you can think of g as the name of the result set of the CTE, which will then be joined to
WITH g as
( SELECT order_number, min(type) as low_type
FROM bookings
GROUP BY order_number
)
SELECT b.*
FROM g
JOIN bookings b ON g.order_number = b.order_number
AND g.low_type = b.type
The JOIN ON conditions will work so that if both types are present then low_type will be 1, and only that type of record will be chosen. If there is only one type it will be identical to low_type.
This should work fine as long as 1 and 2 are the only types allowed in the bookings table. If not then you can simply add a WHERE clause in the CTE and in the outer SELECT.

sql count mismatch

I am not able to understand the SQL query output :
SQL> select distinct(STATUS) from TMP_ORDER_ACTION_PSTN_CP_11035;
InDelivery_SOMBe
In Delivery
Complete
Amended
Cancelled
Failed InComplete
1 SQL> select count(*) from TMP_ORDER_ACTION_PSTN_CP_11035 where
STATUS='Complete';
1484
2 SQL> select count(*) from TMP_ORDER_ACTION_PSTN_CP_11035 where STATUS
!= 'Complete';
3167
3 SQL> select count(*) from TMP_ORDER_ACTION_PSTN_CP_11035;
5091
The sum of count for the 1 and 2 queries should be same as the total count(3 query).Why is the sum differing from the whole count?
It seems like a dump question but i dont know why is this happening.
Please note that My question is not related to null check at all.It is the that
sum(1+2)=3.1484+3167 !=5091.Why is the result different?
My guess is NULL values, which match none of your WHERE clauses, including the last one. Try
select count(*) from TMP_ORDER_ACTION_PSTN_CP_11035 where STATUS is null;
where status = null is never true, nor is where null = null. You have to use is null.
The sum of count for the 1 and 2 queries should be same as the total count(3 query).Why is the sum differing from the whole count?
No, because the records with NULL are not matching query 1 or query 2, but they are counted in query 3.
1 + 2 + IS NULL should equal 3.
WHERE STATUS = NULL won't work. Nothing equals NULL.
Try IS instead of =...
select count(*) from TMP_ORDER_ACTION_PSTN_CP_11035 where STATUS IS null
Try this:
Assuming p_key is a primary key for the table,
select count(p_key) from TMP_ORDER_ACTION_PSTN_CP_11035 where STATUS='Complete';
select count(p_key) from TMP_ORDER_ACTION_PSTN_CP_11035 where STATUS <> 'Complete';
select count(p_key) from TMP_ORDER_ACTION_PSTN_CP_11035 ;