SQL respect order rows in IN clause - sql

I have a table like this:
CREATE TABLE A
(
pk int,
fk int,
col text,
sort_index int
)
and I have a query like this:
select b.fk from A where A.col in ('a','b', 'c')
group by b.fk
but I want only the b.fk that contains all elements in IN clause in order (using the column sort_index).
Is this possible with SQL? If so, how? (Oracle)
For example, I have this data
pk fk col sort_index
1 1 a 1
2 1 c 2
3 1 b 3
4 2 a 1
5 2 b 2
6 2 c 3
I want just the fk 2 because it havs all col in IN and respect the order.

In case you can modify the IN values before executing the query , then this query may work.
SELECT DISTINCT A1.FK
FROM A A1
WHERE A1.COL IN ('a', 'b', 'c')
and (SELECT WM_CONCAT(A2.COL)
FROM A A2
WHERE A2.FK = A1.FK) = 'a,b,c'
For this you will have to pass the IN values as comma separated quoted values('a', 'b', 'c') and only comma separated values (a,b,c).
Hope it helps

Related

Combine SQL Select Lines into "Groups"

I have the following problem,
I have an audit system, which saves the ID of at most three companies for each Audit onde the database line, but it is possible to have up to 15 companies in an audit.
Criteria to determine if group audit
IF
A record has data in Audited_Company2 AND/OR Audited_Company3
THEN
Find additional records where:
Auditor_ID AND Audit_Type AND Audit_Date all match the record found above AND
IF
Records matching criteria are found:
1.Take Audited_Company1-3 from all other matching records and insert them into Audited_Company4-15
Do not show any audits that have had Audited_Company fields merged into another record in the view
However, I have no idea how to I merge 2 or more SQL Lines n a select result like they asked
You can use UNPIVOT to normalize your data and then PIVOT to denormalize it again. Below is a sample query that combines the two. It uses ROW_NUMBER() with appropriate partitioning and ordering conditions to assign sequence numbers to the data for use in the final pivot.
DECLARE #Unnormalized TABLE (Id INT, Value1 VARCHAR(100), Value2 VARCHAR(100), Value3 VARCHAR(100))
INSERT #Unnormalized
VALUES
(1, 'A', 'B', 'C'),
(1, 'Z', 'Y', NULL),
(1, 'X', NULL, NULL),
(2, 'Red', 'Green', NULL),
(2, 'Blue', NULL, NULL)
SELECT P.Id, Value1 = P.[1], Value2 = P.[2], P.[3], P.[4], P.[5], P.[6], P.[7], P.[8], P.[9]
FROM (
SELECT U.Id, U.Value, Sequence = ROW_NUMBER() OVER(PARTITION BY U.ID ORDER BY U.Value)
FROM (SELECT * FROM #Unnormalized) D
UNPIVOT (Value FOR Col IN (Value1, Value2, Value3)) U
) A
PIVOT (MAX(Value) FOR Sequence IN ([1],[2],[3],[4],[5],[6],[7],[8],[9])) P
Results:
Id
Value1
Value2
3
4
5
6
7
8
9
1
A
B
C
X
Y
Z
NULL
NULL
NULL
2
Blue
Green
Red
NULL
NULL
NULL
NULL
NULL
NULL
You should be able to expand on the above to suit your specific needs.
For more information, take a look at the documentation at FROM - Using PIVOT and UNPIVOT.

SQL - Select from column A based on values in column B

Lets say I have a table with 2 columns (a, b) with following values:
a b
--- ---
1 5
1 NULL
2 NULL
2 NULL
3 NULL
My desired output:
a
---
2
3
I want to select only those distinct values from column a for which every single occurrence of this value has NULL in column b. Therefore from my desired output, "1" won't come in because there is a "5" in column b even though there is a NULL for the 2nd occurrence of "1".
How can I do this using a TSQL query?
If I understand correctly, you can do this with group by and having:
select a
from t
group by a
having count(b) = 0;
When you use count() with a column name, it counts the number of non-NULL values. Hence, if all values are NULL, then the value will be zero.
It's fairly simple to do:
SELECT A
FROM table1
GROUP BY A
HAVING COUNT(B) = 0
Grouping by A results in all the rows where the value of A is identical to be transferred into a single row in the output. Adding the HAVING clause enables to filter those grouped rows with an aggregate function. COUNT doesn't count NULL values, so when it's 0, there are no other values in B.
Two more ways to do this:
SELECT a
FROM t
EXCEPT
SELECT a
FROM t
WHERE b IS NOT NULL ;
This would use an index on (a, b):
SELECT a
FROM t
GROUP BY a
WHERE MIN(b) IS NOT NULL ;
Try it like this:
DECLARE #tbl TABLE(a INT, b INT);
INSERT INTO #tbl VALUES(1,5),(1,NULL),(2,NULL),(2,NULL),(3,NULL);
--Your test data
SELECT * FROM #tbl;
--And this is what you want - hopefully...
SELECT DISTINCT tbl.a
FROM #tbl AS tbl
WHERE NOT EXISTS(SELECT * FROM #tbl AS x WHERE x.a=tbl.a AND b IS NOT NULL)
To turn your question on it's head, you want the values from column a where there are no non-null values for that value in column b.
select distinct a
from table1 as t1
where 0 = (select count(*)
from table1 as t2
where t1.a = t2.a
and b is not null)
Sample fiddle is here: http://sqlfiddle.com/#!6/5d1b8/1
This should do it:
SELECT DISTINCT a
FROM t
WHERE b IS NULL
AND a NOT IN (SELECT a FROM t WHERE b IS NOT NULL);

Select Condition Based on Multiple rows

I have a Table Like this:
TableA
----------------------------
ID - Name - PatID
1 A 10
2 B 10
3 A 11
4 A 12
5 B 13
I want to select All Such PatID Which has Name=A and Name = B.
So i should only get 10 as result.
What should be query for this?
You should be able to use the following query to get the result:
select patid
from tablea
where name in ('A', 'B')
group by patid
having count(distinct name) = 2;
See SQL Fiddle with Demo
If you need information from the A group and the B group you could also do it like this:
SELECT AGroup.ID AS AId, BGroup.ID AS BId
FROM TableA AGroup
JOIN TableB BGroup
ON AGroup.Name = 'A'
AND BGroup.Name = 'B'
AND AGroup.PatID = BGroup.PatID
This also retains duplicates if you have more than one entry, for Name = A and PatID = 10 for example.

sql query logic

I have following data set
a b c
`1` 2 3
3 6 9
9 2 11
As you can see column a's first value is fixed (i.e. 1), but from second row it picks up the value of column c of previous record.
Column b's values are random and column c's value is calculated as c = a + b
I need to write a sql query which will select this data in above format. I tried writing using lag function but couldn't achieve.
Please help.
Edit :
Column b exists in table only, a and c needs to calculated based on the values of b.
Hanumant
SQL> select a
2 , b
3 , c
4 from dual
5 model
6 dimension by (0 i)
7 measures (0 a, 0 b, 0 c)
8 rules iterate (5)
9 ( a[iteration_number] = nvl(c[iteration_number-1],1)
10 , b[iteration_number] = ceil(dbms_random.value(0,10))
11 , c[iteration_number] = a[iteration_number] + b[iteration_number]
12 )
13 order by i
14 /
A B C
---------- ---------- ----------
1 4 5
5 8 13
13 8 21
21 2 23
23 10 33
5 rows selected.
Regards,
Rob.
Without knowing the relation between the rows ,how can we calculate the sum of the previous row a and b column to current row a column .I have created two more column id and parent in the table to find the relation between the two rows.
parent is the column which tell us about the previous row ,and id is the primary key of the row .
create table test1 (a number ,b number ,c number ,id number ,parent number);
Insert into TEST1 (A, B, C, ID) Values (1, 2, 3, 1);
Insert into TEST1 (B, PARENT, ID) Values (6, 1, 2);
Insert into TEST1 (B, PARENT, ID) Values (4, 2, 3);
WITH recursive (a, b, c,rn) AS
(SELECT a,b,c,id rn
FROM test1
WHERE parent IS NULL
UNION ALL
SELECT (rec.a+ rec.b) a
,t1.b b
,(rec.a+ rec.b+t1.b) c
,t1.id rn
FROM recursive rec,test1 t1
WHERE t1.parent = rec.rn
)
SELECT a,b,c
FROM recursive;
The WITH keyword defines the name recursive for the subquery that is to follow
WITH recursive (a, b, c,rn) AS
Next comes the first part of the named subquery
SELECT a,b,c,id rn
FROM test1
WHERE parent IS NULL
The named subquery is a UNION ALL of two queries. This, the first query, defines the starting point for the recursion. As in my CONNECT BY query, I want to know what is the start with record.
Next up is the part that was most confusing :
SELECT (rec.a+ rec.b) a
,t1.b b
,(rec.a+ rec.b+t1.b) c
,t1.id rn
FROM recursive rec,test1 t1
WHERE t1.parent = rec.rn
This is how it works :
WITH query: 1. The parent query executes:
SELECT a,b,c
FROM recursive;
This triggers execution of the named subquery. 2 The first query in the subquery's union executes, giving us a seed row with which to begin the recursion:
SELECT a,b,c,id rn
FROM test1
WHERE parent IS NULL
The seed row in this case will be for id =1 having parent is null. Let's refer to the seed row from here on out as the "new results", new in the sense that we haven't finished processing them yet.
The second query in the subquery's union executes:
SELECT (rec.a+ rec.b) a
,t1.b b
,(rec.a+ rec.b+t1.b) c
,t1.id rn
FROM recursive rec,test1 t1
WHERE t1.parent = rec.rn

Updating duplicate values;

I have a table which contains unique indexes;lets say
A B
1 1
1 2
1 3
1 4
And i want to update the B column,since sql updates them one by one if it tries to update the first column to 2 for ex i get::
A B
1 2
1 2
1 3
1 4
And as a result i would get two duplicate values at the 1st and 2nd row and of course an error message.
And i should update the table like that:
A B
1 2
1 1
1 3
1 4
So whats the course of action i should follow in case of this scenario?
Regards.
Maybe i should update the question abit:
What if i wanted to change the b column completely; such as:
A B
1 4
1 2
1 3
1 1
Try this
UPDATE tbl
SET B = 3 - B
WHERE A = 1 AND B IN (1, 2)
Or, generaly, you can use something like that:
UPDATE tbl
SET B = CASE B
WHEN 1 THEN 2
WHEN 2 THEN 1
END
WHERE A = 1 AND B IN (1, 2)
Another way:
add column C
through your loop fill C column with new values
update field B from C:
UPDATE tbl
SET B = C
The solution is to do the swap in a single statement:
UPDATE YOUR_TABLE
SET B = (CASE B WHEN 1 THEN 2 ELSE 1 END)
WHERE A = 1 AND B IN (1, 2)
--- EDIT ---
To update several rows at once, you can do a JOIN-update from the temporary table:
CREATE TABLE #ROWS_TO_UPDATE (
A int,
B int,
NEW_B int,
PRIMARY KEY (A, B)
);
INSERT INTO #ROWS_TO_UPDATE (A, B, NEW_B) VALUES (1, 1, 4);
INSERT INTO #ROWS_TO_UPDATE (A, B, NEW_B) VALUES (1, 2, 3);
INSERT INTO #ROWS_TO_UPDATE (A, B, NEW_B) VALUES (1, 3, 2);
INSERT INTO #ROWS_TO_UPDATE (A, B, NEW_B) VALUES (1, 4, 1);
UPDATE YOUR_TABLE
SET B = NEW_B
FROM
YOUR_TABLE JOIN #ROWS_TO_UPDATE
ON YOUR_TABLE.A = #ROWS_TO_UPDATE.A AND YOUR_TABLE.B = #ROWS_TO_UPDATE.B;
DROP TABLE #ROWS_TO_UPDATE;
The above code transforms the following data...
A B
1 1
1 2
1 3
1 4
...to this:
A B
1 4
1 2
1 3
1 1
If I understand well, you have a primary key composed of two columns, and you want to swap the two first rows' PK.
If you don't have foreing keys which refers to this primary key, simply change one of the keys to a temporary unused value:
A B
1 10000
1 2
then change the second row:
A B
1 10000
1 1
Finally, change the first one:
A B
1 2
1 1
If you have objects depending on this primary key, you would have to make a copy of the other columns (for example the other columns of 1 1) to a "temporary row", copy the data of the second (1 2) to the first (1 1) and finally copy the "temporary row" to the second (1 2)
This all dependes on how and what you're exactly trying to do. Is it a stored procedure, is it a query... You should show more context.
You could apply this technique to an unlimited number of rows. You can also create a temporary table with key equivalences, and update your table from tha temporary table. So, it will be done in an atomic operation, and it won't violate the PK.
create table T
(A int, B int, C char(5),
primary key (A,B))
insert into T values(1,1,'first')
insert into T values(1,2,'secon')
insert into T values(1,3,'third')
create table #KeyChanges
(A int, B int, newA int, newB int)
insert into #KeyChanges values(1,1,1,3)
insert into #KeyChanges values(1,2,1,1)
insert into #KeyChanges values(1,3,1,2)
update T set T.A = KC.newA, T.B = KC.newB
from T
left join #KeyChanges as KC on T.A = KC.A and T.B = KC.B