Pivot table Non-unique values - sql

I have two tables that I want to join together into 1 row by accessruleId for an ssrs report. The issue is FieldName has dynamic values and the same fieldName could appear more than once It seems like Pivot table is what I want but examples I've looked at is pivoting off a unique value and doing an aggregate function. Below is the output for query 1 and 2 and I want to combine the results so it looks like screenshot 3. If a given fieldname shows up more than once (businessArea in this case) I want to make the values comma delimited. Any links to examples similar to my need would be greatly appreciated. I'm using sql server 2016
Query 1
select ar.AccessRuleId, ar.EffectiveDate, ar.TermDate, ar.CreatedByUser, ar.LastUpdatedUser
from [AccessRule].[AccessRule] ar
where ar.AccessRuleId = 1
Query 2
select rf.FieldName, ro.[Value]
from [AccessRule].[RuleOperation] ro
join [AccessRule].[RuleField] rf on ro.FieldId = rf.RuleFieldId
where ro.AccessRuleId = 1

Related

SQLite: Matching a column containig a single string to another column containing comma-separated values [duplicate]

I have a table with a column that has concatenated values like this
Table CHILD:
ChildId Values
2 x123,j455
3 f456,z789
4 m333,y567
5 x123,h888
And I have a master table MASTER that has
Table MASTER:
MainValues
x123
f456
y567
I need to get a query that'll select the following data
ChildId MainValues
2 x123
3 f456
4 y567
5 x123
Basically match value from MASTER in child values and return only the master value. How can I do this ? I have tried IN and LIKE clause matching with second table but that doesnt help much since the values are csv. Is there a way to split and match in sqlite ?
EDIT: Table and column names are fictional and intended just to explain this question better
Use a regular expression:
SELECT ChildId,MainValues FROM CHILD INNER JOIN MASTER WHERE ','||[Values]||',' like '%,'||MainValues||',%'
Also, please refrain from using keywords like values for column names...
Unfortunately SQLite doesn't have a function to find the index of a character from a string. So you have to rely on something else. Idan's method is good too but can be slower. You may try this:
SELECT c.childID, m.mainvalues
FROM CHILD c
JOIN MASTER m
WHERE m.mainvalues = substr(c.ivalues, -length(c.ivalues), 4)
OR m.mainvalues = substr(c.ivalues, 6);
I have used 4 and 6 assuming your number of characters before and after the ,. If that's not fixed you can try:
SELECT c.childID, m.mainvalues
FROM CHILD c
JOIN MASTER m
WHERE m.mainvalues = substr(c.ivalues, -length(c.ivalues), length(m.mainvalues))
OR m.mainvalues = substr(c.ivalues, length(m.mainvalues) + 2);

sql how to convert multi select field to rows with totals

I have a table that has a field where the contents are a concatenated list of selections from a multi-select form. I would like to convert the data in this field into in another table where each row has the text of the selection and a count the number of times this selection was made.
eg.
Original table:
id selections
1 A;B
2 B;D
3 A;B;D
4 C
I would like to get the following out:
selection count
A 2
B 3
C 1
D 2
I could easily do this with split and maps in javascript etc, but not sure how to approach it in SQL. (I use Postgresql) The goal is to use the second table to plot a graph in Google Data Studio.
A much simpler solution:
select regexp_split_to_table(selections, ';'), count(*)
from test_table
group by 1
order by 1;
You can use a lateral join and handy set-returning function regexp_split_to_table() to unnest the strings to rows, then aggregate and count:
select x.selection, count(*) cnt
from mytable t
cross join lateral regexp_split_to_table(t.selections, ';') x(selection)
group by x.selection

How can I use a row value to dynamically select a column name in Oracle SQL 11g?

I have two tables, one with a single row for each "batch_number" and another with defect details for each batch. The first table has a "defect_of_interest" column which I would like to link to one of the columns in the second table. I am trying to write a query that would then pick the maximum value in that dynamically linked column for any "unit_number" in the "batch_number".
Here is the SQLFiddle with example data for each table: http://sqlfiddle.com/#!9/a1c27d
For example, the maximum value in the DEFECT_DETAILS.SCRATCHES column for BATCH_NUMBER = A1 is 12.
Here is my desired output:
BATCH_NUMBER DEFECT_OF_INTEREST MAXIMUM_DEFECT_COUNT
------------ ------------------ --------------------
A1 SCRATCHES 12
B3 BUMPS 4
C2 STAINS 9
I have tried using the PIVOT function, but I can't get it to work. Not sure if it works in cases like this. Any help would be much appreciated.
If the number of columns is fixed (it seems to be) you can use CASE to select the specific value according to the related table. Then aggregating is simple.
For example:
select
batch_number,
max(defect_of_interest) as defect_of_interest,
max(defect_count) as maximum_defect_count
from (
select
d.batch_number,
b.defect_of_interest,
case when b.defect_of_interest = 'SCRATCHES' then d.scratches
when b.defect_of_interest = 'BUMPS' then d.bumps
when b.defect_of_interest = 'STAINS' then d.stains
end as defect_count
from defect_details d
join batches b on b.batch_number = d.batch_number
) x
group by batch_number
order by batch_number;
See Oracle example in db<>fiddle.

Why aren't these two sql statements returning same output?

I'm just getting started with sql and have the objective to transform this:
select X.persnr
from Pruefung X
where X.persnr in (
select Y.persnr
from pruefung Y
where X.matrikelnr <> Y.matrikelnr)
output:
into the same output but using a form of join. I tried it the way below but I can't seem to get "rid" of the cartesian product as far as i can see. Or maybe i misunderstood the above statement what it should actually do. For me the above says "for each unique matrikelnr display all corresponding persnr".
select X.persnr
from Pruefung X
join pruefung y on x.persnr=y.persnr
where x.matrikelnr<>y.matrikelnr
output: A long list (I don't want to fill the entire question with it) - i am guessing the cartesian product from the join
This is the relation I am using.
Edit: Distinct (unless i am using it in the wrong place) won't work because then persnr is only displayed once, thats not the objective though.
Your initial query actually does:
select persnr from Pruefung if the same persnr exists for a a diferent matrikelnr.
"for each unique matrikelnr display all corresponding persnr"
This is achieved using aggregation:
Depending on the DBMS you are using you could use something like (SQL Server uses STRING_AGG, but MySQL uses GROUP_CONCAT)
SELECT matrikelnr,STRING_AGG(matrikelnr,',')
GROUP BY matrikelnr
You cannot easily achieve what you got from a correlated query (your first attempt) by using a join.
Edit:
A join does not result in a "Cartesian product" expect from when there is no join condition (CROSS JOIN).
A join matches two sets based on a join condition. The reason why you get more entries is that the join looks at the join key (PERSNR) and does its matching.
For example for 101 you have 3 entries. That means you will get 3x3 reults.
You then filter out the results for the cases where X.matrikelnr <> Y.matrikelnr If we assume matrikelnr is unique that would mean the row matched with itself. so you will lose 3 results ending up with 3x3 - 3 = 6.
If you want to achieve something in SQL you must first define what you are expecting to use and then use the appropiate tools (in this case correlated queries not joins)
You can write your 1st query with EXISTS instead of IN like:
select X.persnr
from Pruefung X
where exists (
select 1
from pruefung Y
where X.persnr = Y.persnr and X.matrikelnr <> Y.matrikelnr
)
This way it's obvious that this query means:
return all the persnrs of the table for which there exists another
row with the same persnr but different matrikelnr
For your sample data the result is all the persnrs of the table.
Your 2nd query though, does something different.
It links every row of the table with all the rows of the same table with the same persnr but different matrikelnr.
So for every row of the table you will get as many as rows as there are for the same persnrs but different matrikelnrs.
For example for the 1st row with persnr = 101 and matrikelnr = 8532478 you will get 2 rows because there are 2 rows in the table with persnr = 101 and matrikelnr <> 8532478.
You are right. It's the cartesian product's fault. Suppose you have persnr 1,1,1,2,2,2 in the first table and persnr 1,1,1,2,2 in the second. How many lines are you expecting to be returned?
In pdeuso-code it would go like this
Select
...
WHERE persnr in (second table)
-- 6 lines
Select persnr
FROM ...
JOIN ... ON a.persnr = b.persnr
-- 3X3 + 3X2 = 15 lines.
SELECT DISTINCT persnr
FROM ...
JOIN ... ON a.persnr = b.persnr
-- 2 lines (1 and 2)
Take your pick

Concatenating codes to obtain sum

I've been for tha past 2 days trying to solve this problem but can't even seem to find the right terms to google it.
I have 3 tables.
This one, with client codes that changed:
ActualCode=111111111 PreviousCode=44444444
And these two tables with value 1 and value 2:
PreviousCode=11111111, Value1= 50,00, Value2= 0,00
ActualCode=44444444 , Value1= 0,00, Value2 = 50,00
I need to sum the values for each relation of Previous and Actual codes from the first table.
I.E.
For
ActualCode=11111111, PreviousCode=44444444
I need to be able to get:
Code=11111111 Value1=50,00 Value2=50,00
Looking forward for your answer :D
Thanks,
P
You can join the tables and sum the values:
select c.actualcode,
sum(ac.value1) + sum(pc.value1) as value1,
sum(ac.value2) + sum(pc.value2) as value2
from codes c
join actualcodes ac on c.actualcode = ac.actualcode
join previouscodes pc on c.previouscode = pc.previouscode
group by c.actualcode;
Rextester Demo
If you could have values in the main table that don't have corresponding rows in the values tables, then you should use outer joins instead.