How to compare two rows of a table - sql

I have a sample table with input as shown. In actual it has large amounts of data. The input and output as shown:
I/P- O/P-
|ID | Role | Status | |ID | Role | Status | Final |
|:-:|:----:|:------:| |:-:|:----:|:------:|:-----:|
| 1 | ABC | Pass | | 1 | ABC | Pass | 0 |
| 2 | PQR | Pass | | 2 | PQR | Pass | 0 |
| 1 | ABC | Fail | | 1 | ABC | Fail | 0 |
| 3 | PQR | Fail | | 3 | PQR | Fail | 0 |
| 1 | XYZ | Fail | | 1 | XYZ | Fail | 1 |
| 3 | PQR | Fail | | 3 | PQR | Fail | 1 |
| 3 | XYZ | Pass | | 3 | XYZ | Pass | 0 |
| 4 | XYZ | Fail | | 4 | XYZ | Fail | 1 |
So for a 'ID' (ex. ID=1) if Role is same for two or more records (ex. Role = 'ABC') then will status field. If for any of the selected record 'Status' = 'Pass' then will create a new field named Final with value 0 for all records(if for any of the record Status = 'Pass')
else will keep it 1(if there is no record with 'Status' = 'Pass'.
I know this we can do with Case statement while comparing columns. But not sure how to do with rows. Can someone please help me.
Thanks.

You can do an exists check. And tis coud be written in different ways depending on your backend which you didn't specify:
select Id, Role, Status,
case when exists (select * from myTable t2
where t1.Id = t2.Id
and t1.Role = t2.Role
and t2.Status = 'Pass') then 0 else 1 end as Final
from myTable t1;
DBFiddle demo
PS: Either your sample output is wrong or your explanation. You may need to change the where part depending on your actual need.

Related

SQL: Check if multiple records exist in multiple tables

In my database, I have a table with a many-to-many relationship to several other tables. I'd like to know, for several records at a time, whether an item exists in each of the other tables. Here's a simple example diagram:
---------------
| base_table |
---------------
| key | name |
---------------
| 1 | item1 |
| 2 | item2 |
| 3 | item3 |
| 4 | item4 |
---------------
-------------------------------
| table_2 |
-------------------------------
| key | base_key | other_key |
-------------------------------
| 1 | 1 | 1 |
| 2 | 1 | 2 |
| 3 | 1 | 3 |
| 4 | 2 | 1 |
| 5 | 2 | 4 |
| 6 | 4 | 4 |
-------------------------------
-------------------------------
| table_3 |
-------------------------------
| key | base_key | other_key |
-------------------------------
| 1 | 2 | 1 |
| 2 | 3 | 2 |
-------------------------------
And then I'm looking for output like this:
-----------------------------------
| name | in_table_2 | in_table_3 |
-----------------------------------
| item1 | true | false |
| item2 | true | true |
| item3 | false | true |
| item4 | true | false |
-----------------------------------
I'm using MS SQL Server.
You can use union all and aggregation to get which keys are in which tables:
select base_key, max(in_2) as in_2, max(in_3) as in_3
from ((select distinct base_key, 1 as in_2, 0 as in_3
from table2
) union all
(select distinct base_key, 0 as in_2, 1 as in_3
from table3
)
) t
group by base_key;
This returns "1" if the key is in the table and "0" if it is not. SQL Server does not have boolean types and it seems silly to create a string for this purpose.
If you actually need the name instead of the key value, just join it in.
Though I liked #GordonLindoff's post, I thought the following would have worked just as well:
SELECT DISTINCT
b.Name,
in_table_2 = CASE WHEN c.Base_key IS NULL THEN 0 ELSE 1 END,
in_table_3 = CASE WHEN d.Base_key IS NULL THEN 0 ELSE 1 END
FROM Base_Table b
LEFT JOIN Table_2 c
ON b.key = c.Base_Key
LEFT JOIN Table_3 d
ON b.key = d.Base_Key;
I'd also reiterate his comment about 1's and 0's in SQL. If you really, really need "True" or "False" in your display, do it on the front end, or change the 0 and 1 in the case statements to False and True, respectively.
Anyone have any objections to this?
I did to a SQLFiddle, listed here. http://sqlfiddle.com/#!18/d6547/28

SQL Get cases related to a user and the number of files attached to that case

Hi everyone got a little stuck on an sql query. I have four tables
users
+----+------------+-----------+--------+
| id | first_name | last_name | active |
+----+------------+-----------+--------+
| 1 | Joe | Bloggs | 1 |
| 2 | John | Doe | 1 |
| 3 | Dave | Smith | 1 |
+----+------------+-----------+--------+
cases
+----+-----------+-------------+
| id | case_code | case_name |
+----+-----------+-------------+
| 1 | THEC12C | Test Case 1 |
| 2 | ABCD23A | Test Case 2 |
+----+-----------+-------------+
case_creditors
+----+---------+-------------+
| id | case_id | creditor_id |
+----+---------+-------------+
| 1 | 1 | 3 |
| 2 | 2 | 1 |
+----+---------+-------------+
case_files
+----+---------+----------+-----------+
| id | case_id | filename | file type |
+----+---------+----------+-----------+
| 1 | 1 | test.pdf | pfd |
| 2 | 2 | file.txt | txt |
| 3 | 2 | word.doc | doc |
+----+---------+----------+-----------+
When a user logs in i need to show a table with the users accociated cases the number of files attached to that case so if Joe Blogs loged in head see the following table
+-----------+-------------+-------+
| Case Code | Case Name | Files |
+-----------+-------------+-------+
| ABCD23A | Test Case 2 | 2 |
+-----------+-------------+-------+
ive been trying to write the sql statement to do this but am getting stuck on the query and wandered if someone could help give me some pointers. the sql ive gor so far
SELECT * FROM cases
(SELECT COUNT(*) FROM case_files WHERE case_files.case_id = cases.id) as Files
JOIN case_creditors ON cases.id = case_creditors.case_id
WHERE case_creditors.creditor_id = 1
managed to sort this with
SELECT
ips_case.*,
COUNT(case_files.file_id) AS Files
FROM
ips_case
LEFT JOIN case_files ON ips_case.id = case_files.case_id
JOIN case_creditors ON ips_case.id = case_creditors.case_id
WHERE
case_creditors.creditors_id = 4
GROUP BY
ips_case.id

Marking records with 1 on first occurence of unique value

I have a table that I'd like to add a column to that shows a 1 on the first occurrence of a given value for the record within the dataset.
So, for example, if I was using the ID field as where to look for unique occurrences, I'd want a "FirstOccur" column (like the one below) putting a 1 on the first occurrence of a unique ID value in the dataset and just ignoring (leaving as null) any other occurrence:
| ID | FirstOccur |
|------|--------------|
| 1 | 1 |
| 1 | |
| 1 | |
| 2 | 1 |
| 2 | |
| 3 | 1 |
| 4 | 1 |
| 4 | |
I have a working 2-step approach that first applies some ranking sql that will give me something like this:
| ID | FirstOccur |
|------|--------------|
| 1 | 1 |
| 1 | 2 |
| 1 | 3 |
| 2 | 1 |
| 2 | 2 |
| 3 | 1 |
| 4 | 1 |
| 4 | 2 |
..and I just apply some update SQL to null any value above 1 to get the desired result.
I was just wondering if there was a (simpler) one-hit approach.
Assuming you have a creation date or auto incremented id or something that specifies the ordering, you can do:
update t
set firstoccur = 1
where creationdate = (select min(creationdate)
from t as t2
where t2.id = t.id
);

Create a combined list from two tables

I have a table with CostCenter_ID (int) and a second table with Process_ID (int).
I'd like to combine the results of both tables so that each cost center ID is assigned to all process IDs, like so:
|CostCenterID | ProcessID |
---------------------------
| 1 | 1 |
| 1 | 2 |
| 1 | 3 |
| 2 | 1 |
| 2 | 2 |
| 2 | 3 |
| 3 | 1 |
| 3 | 2 |
| 3 | 3 |
I've done it before but I'm drawing a blank. I've tried this:
SELECT CostCenter_ID,NULL FROM dbo.Cost_Centers
UNION ALL
SELECT NULL,Process_ID FROM dbo.Processes
which returns this:
|CostCenterID | ProcessID |
---------------------------
| 1 | NULL |
| NULL | 1 |
| NULL | 2 |
| NULL | 3 |
Try:
select a.CostCenterID, b.ProcessID
from table1 a
cross join table2 b
or:
select a.CostCenterID, b.ProcessID
from table1 a
,table2 b
NB: cross join is the better method as it makes it clearer to the reader what your intentions are.
More info (with pics) here: http://www.w3resource.com/sql/joins/cross-join.php

Compare two tables and get the difference between them

I have two tables: TableA and TableB.
I need to compare two particular column(AnsId & Content) from two tables and get their difference.
In case there is no difference is found then I should return 'process success', else return 'Failure'
TableA
+--------+-----------+---------+-------------+
| Id | RSCId | AnsId | Content |
+--------+-----------+---------+-------------+
| 1 | 12 | 1 | Test data. |
| 2 | 12 | 0 | Sample Test.|
| 3 | 12 | 5 | Test data. |
| 4 | 12 | 7 | Test Data. |
| 5 | 12 | 46 | Test datas. |
+--------+-----------+---------+-------------+
TableB
+--------+-----------+---------+-------------+
| Id | RSCId | AnsId | Content |
+--------+-----------+---------+-------------+
| 1 | 35 | 2 | Test . |
| 2 | 35 | 0 | Sample Test.|
| 3 | 35 | 5 | Test data. |
| 4 | 35 | 7 | Test Data. |
| 5 | 35 | 46 | Test datas. |
+--------+-----------+---------+-------------+
Please help me out.
select case when sum(case when a.ansid is null or b.ansid is null
then 1
end) > 0
then 'mismatch'
else 'ok'
end as result
from tableA a
full outer join tableB b on a.ansid = b.ansid and a.content = b.content