Fact table joins - sql

I have two facttables A and B.
A has a positionkey column in it and B has 4 columns called position_1,position_2,
position_3,position_4 and has an indicator of that position. For eg, if B has 2 under position_1 it means two people with position 1 were assigned. if B has 1 under position_2 it means one person with position 2 was assigned.
I would want to join these two tables by position and other keys.
Is there a possibility to do this?

You could use a CASE in your JOIN conditions.
ON a.PositionValue = CASE
WHEN a.PositionKey=1 THEN b.Position_1
WHEN a.PositionKey=2 THEN b.Position_2
etc...
END

Related

Getting ranges of arbitrary strings in SQL based on sequence dictated in a separate table

Consider the following dataset (may look weird but want to land my point that the strings are arbitrary):
Table A
TicketId
StartAnimal
EndAnimal
1
Monkey
Bee
1
Lion
Buffalo
Table B
Animal
Sequence
Monkey
1
Zebra
2
Bee
3
Turtle
4
Lion
5
Buffalo
6
Is it possible to retrieve the animals that correspond to Ticket ID 1 based on the different "ranges" in each of its rows? For example,for Ticket ID 1 the following animals should be retrieved: Monkey, Zebra, Bee, Lion, Buffalo.
As you can see the animal strings themselves have no order logic to it, but the sequence can be leveraged for it. I'm just failing to come up with how to reference it for each row in a single query.
Edit
As an edge case, sometimes the EndAnimal might not even have a sequence to start with, in which case only the StartAnimal should be returned. As an example, assuming Bee is not in the sequence table, we should only get Monkey, Lion and Buffalo. Is that something SQL can handle?
Thanks!
There are numerous ways, one such way is to inner join the tables to find the corresponding start and end sequences and then find those rows that qualify:
with s as (
select bs.Sequence s1, IsNull(be.sequence,1) s2, a.ticketId
from a left join b bs on bs.animal = a.StartAnimal
left join b be on be.Animal = a.EndAnimal
)
select b.Animal
from b
join s on b.Sequence >=s1 and b.Sequence <= s2
where s.ticketId = 1
order by b.Sequence;
Example Fiddle

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);

Filter by one column then count unique value in another column in SQL

I would like to filter data by column Base =1 and then count the number of unique values in another column 'Animal' in SQL, data:
Animal Base Value
1 A 1 X
2 B 1 X
3 A 2 Y
4 A 3 V
Expected output in this case is 2 from the first two rows.
Simpler than you may have thought:
SELECT count(DISTINCT Animal)
FROM tbl
WHERE Base = 1;
Should work in any halfway decent RDBMS including your undisclosed one. (You may have to enclose column names in double-quotes.)
This should do it, assuming the table is named animals:
select count(*) from (select distinct Animal from animals where Base=1) tb1;

How to rollup specific strings in a query

I would like to combine rows with duplicates in a specific column such that specific items are listed and others are excluded
I have attempted to use string_agg, group_by and self joins, I feel like I may simply need a better self join but I am not sure.
one two three four
1 1 a NULL
2 4 b e
3 7 c x
3 7 c z
I would like it to look something like this (with the elements that were the same remaining unsegregated)
one two three
1 1 a NULL
2 4 b e
3 7 c x,z
If you are using MySQL :
SELECT one, two, three, GROUP_CONCAT(four)
FROM table
GROUP BY one, two, three
Otherwise, this is a bad thing to do in a RDBMS because this is not a relationnal operation.
You should do this in the client-side of your project.

SQL: Populating Column B where Column A has a match elsewhere in Column B

I’m somewhat of a newbie to SQL queries, especially anything containing logic, and although I've searched for hours finding the exact terms to search for is not easy in this case! I have a relatively simple one, I’m sure:
A table has 2 columns, and each row contains data about a function in a program. Some functions have a parent function associated (for grouping). Column A is the unique function ID. Column B indicates, when applicable, the parent function’s ID. All parent function IDs are independent and valid function IDs that exist elsewhere in column A.
For reporting purposes I need to list the functions grouped by their parent ID, listing the parent function with the child functions. I can easily report by parent function ID, but the problem is that a parent function does not know that it is a parent function because its column B is empty!
What I need to do is complete the value in Column B if it is empty and the function is referenced elsewhere as a parent function.
Otherwise stated, for each row that has a null value in Column B:
Take the value from column A
Check for the existence of that value in ANY row on column B
If there is a match, inject the value into column B (so that Column A and B have the same value)
What I have: (Query: SELECT function_id, parent_function FROM functions)
FUNCTION_ID PARENT_FUNCTION
4
13 4
79
138 4
195
314 345
345
What I need to have:
FUNCTION_ID PARENT_FUNCTION
4 4
13 4
79
138 4
195
314 345
345 345
Any Ideas? I can't wait to get more familiar with SQL! Thanks ahead of time.
This should work for you:
UPDATE functions
SET parent_function = function_id
WHERE parent_function IS NULL
AND function_id IN (SELECT parent_function FROM functions)
This will set parent_function equal to function_id where it has not yet been set, and where it appears somewhere in the parent_function column.
If you don't actually want to modify the table data but still return values that you need, you can use similar logic like this:
SELECT f.function_id, COALESCE(f.parent_function, f2.function_id) as parent_function
FROM functions f
LEFT JOIN functions f2
ON f.function_id = f2.function_id
AND f2.function_id IN (SELECT parent_function FROM functions)
maybe you can compare the two table using EXCEPT or INTERSECT
http://msdn.microsoft.com/en-us/library/ms188055.aspx
more tutorials>:
http://www.mssqltips.com/sqlservertip/1327/compare-sql-server-datasets-with-intersect-and-except/
How's this look?
select distinct
t1.funx, t1.parent,
case when t2.parent is null then t1.parent
else t2.parent end as newparent
from
tbl t1 left outer join
tbl t2 on
t1.funx = t2.parent
sqlFiddle