PostgresSQL avoiding cartesian product - sql

I am trying to add a column to an existing table. Basically this is how it looks:
Table 1
value1
value2
value3
value4
Tab2
max1 min1 output1
max2 min2 output2
max3 min3 outpu3
So in function on the interval (min, max) in which value is present, there is an output.
My current code is the following
Select Table1.*,
case when value < max and value > min then output
end new_column
from Table1, Table2
But I end up getting several times the same row (exactly the same). How can I avoid this, or what I am doing wrong ?
This is what I expect to obtain at the end:
Table
value1 output1
value2 output4
value3 output1
...
Thank you

Using a join
select t1.*, t2.output
from Table1 t1
join Table2 t2 on t1.value < t2.max and t1.value > t2.min

Related

Update rows with previous rows

I have a table with a column 'id' which is autoincrement. In some records i have zero values. I want to update them by their previous rows (here previous means id - 1) .
How can i do that?
This query returns those records with zero values:
SELECT * FROM myTable
WHERE col1 = 0
which returns:
id col1 col2 ..... coln
15 0 0 0
23 0 0 0
You could use a correlated subquery:
update mytable t
set col1 = (select t1.col1 from mytable t1 where t1.id = t.id - 1)
where col1 = 0

results of a sub table in the top level query

Not sure how to title this so please feel free to retitle.
I have two tables with a one to many relationship.
Table1
|ID|NAME|...|
Table2
|ID|Table1_ID|StartDate|EndDate|
I am trying to write a query that given a date will return the following
|TABLE1.ID|TABLE1.NAME|are any rows of table 2 in date|
I have a one to many between table 1 and table 2. I want to pass in a date to the query. If any of the many relationships in table 2 have a start date < passed in date and an end date > passed in date or end date is null then I want column 3 of result to be true. Otherwide I want it to be false.
Consider the example
|ID|NAME|...|
| 1|APPLE| ...|
| 2|PEAR| ...|
Table2
|ID|Table1_ID|StartDate|EndDate|
|1|1|01-01-2014|null|
|2|1|01-01-2014|01-02-2014|
|3|2|01-01-2014|01-02-2014|
if I pass in 01-01-2014 then I expect two rows with IDs 1 and 2 and both to be true (all rows match)
if I pass in 01-03-2014 then I expect two rows with ID 1 true (match on first row) and ID 2 to be false (because third row is outside of this date)
I am trying to do this in SQL to eventually convert to JPA. If there are any JPA functions that can do this then that would be good to know. Else I'll do a native query
Any pointers would be great!
Thanks
This should give you what you want:
select x.*, 'PASS' as checker
from table1 x
where exists
(select 'x'
from table2 y
where y.table1_id = x.table1_id
and y.startdate <= '01-01-2014'
and (y.enddate >= '01-01-2014' or y.enddate is null))
union all
select x.*, 'FAIL' as checker
from table1 x
where not exists
(select 'x'
from table2 y
where y.table1_id = x.table1_id
and y.startdate <= '01-01-2014'
and (y.enddate >= '01-01-2014' or y.enddate is null))
I don't know if I understand your question.
So, please, be patient... ;)
Try something like this:
select t1.id, t1.name,
case when t2.Table1_ID is null
then 'false'
else 'true' end as boolean_value
from Table1 t1,
(select distinct Table1_ID
from Table2
where yourdate >= StartDate
and (yourdate <= EndDate or EndDate is null) t2
where t1.id = t2.id (+);

SQL: selecting unique values based on conditions

I have a table containing 5 columns. The first column contains an ID, two columns contain parameters for those IDs with the values 0 or 1, a third column contains a parameter which I need as output, the last column contains a date. The same ID can appear in several rows with different parameters:
ID parameter1 parameter2 parameter3 date
001 0 1 A 01.01.2010
001 0 1 B 02.01.2010
001 1 0 C 01.01.2010
001 1 1 D 01.01.2010
002 0 1 A 01.01.2010
For each unique ID I want to return the value in parameter3, the decision from which row to return this value is based on the values in parameter1 and parameter2 and the date:
If there is a row with both parameters being 0, I want the value in this row.
If there is no such row, I want the value from the row where parameter1 is 0 and parameter2 is 1,
If there is no such row, I want the row where parameter1 is 1 and parameter2 is 0.
Finally, if there is no such row, I want the value from the row with both parameters being 1.
If there is more than one row matching the required conditions, I want the row with the most recent date.
e.g., for the table above, for the ID 001 I would want the second row with the value B in parameter3.
What would be the most effective / fastest way to accomplish this? I tried two approaches so far:
the first one was to select all distinct IDs and then loop through the distinct IDs, using a select statement with the ID in the where clause and then loop through all the rows matching the ID while storing the necessary values in variables.:
foreach
select distinct ID into i_ID from table1
foreach
let o_case = 5
select case
when parameter1 = 0 and parameter2 = 0 then 1
when parameter1 = 0 and parameter2 = 1 then 2
when parameter1 = 1 and parameter2 = 0 then 3
when parameter1 = 1 and parameter2 = 1 then 4
end, parameter3, date
into i_case, i_p3, i_date
from table3
where table3.ID = i_ID
if i_case < o_case
then let o_p3, o_case, o_date = i_p3, i_case, i_date;
else ( if i_case = o_case and i_date > o_date
then let o_p3, o_date = i_p3, i_date;
end if;
end if;
end foreach;
insert into table_output values(i_ID; o_p3);
end foreach;
The second approach was to left join the table four times with itself on the ID and apply the different combinations of the parameter1 & parameter2 as described above in the left joins, then selecting the output via nested nvl clauses:
select ID,
nvl(t1.parameter3,
nvl(t2.parameter3,
nvl(t3.parameter3,
nvl(t4.parameter3)))) parameter3
from table1 t0
left join table1 t1
on t0.ID = t1.ID and t1.parameter1 = 0 and t1.parameter2 = 0
and t1.date = (select max(date) from table1 t1a where t1a.ID = t1.ID)
left join table1 t2
on t0.ID = t2.ID and t2.parameter1 = 0 and t2.parameter2 = 1
and t2.date = (select max(date) from table1 t2a where t2a.ID = t1.ID)
left join table1 t3
on t0.ID = t3.ID and t3.parameter1 = 1 and t3.parameter2 = 0
and t3.date = (select max(date) from table1 t3a where t3a.ID = t3.ID)
left join table1 t4
on t0.ID = t4.ID and t4.parameter1 = 1 and t4.parameter2 = 1
and t4.date = (select max(date) from table1 t4a where t4a.ID = t4.ID)
Both approaches basically worked, however, as the table is really long, they were much too slow. What would you recommend?
PS: DBMS is IBM Informix 10, this unfortunately restricts the range of available functions a lot.
I'm not sure if this is what you wanted, but this could work:
SELECT id, parameter3
FROM (
SELECT id, parameter3, RANK() OVER (
PARTITION BY id, parameter3
ORDER BY parameter1 ASC, parameter2 ASC, date DESC
)
FROM tab
) AS x
WHERE x.rank = 1;
ID parameter1 parameter2 parameter3 date
001 0 1 A 01.01.2010
001 0 1 B 02.01.2010
both of the above rows having same ID, paramaeter1, parameter2 but different paraameter3, it can create trouble for you.

How to SELECT a column composed by some other columns value

I have a daycode column that stores values like 1,2...7
then in a different table I have cols like field1,field2...field7
I can join them on a key, but how do I select the specific fieldX column based on values passed?
Table 1 has the following columns
-------------
id
prodno
field1
field2
field3
field4
field5
field6
field7
Where each fieldX represents a value for monday, tuesday and so on till sunday.
Table 2 has the following columns
-------------
id
prodno
dt
daycode
Update
t2 has columns like field1, field2 ... field7, and daycode values is 1,2 ... 7. We need to concat "field" with the value taken from daycode column.
select table1.id,select [concat('field',table2.daycode)] from table1 join
table2 on table1.id=table2.key
You can create the statement in string an then execute it using execute (#sql)
or You can add a case statement in the select where You will pick the proper column.
Im not sure aobut this but you can try
SELECT t1.id,
CASE
WHEN daycode = 1 THEN t2.field1
WHEN daycode = 2 THEN t2.field2
WHEN daycode = 3 THEN t2.field3
WHEN daycode = 4 THEN t2.field4
END
FROM t1 join t2 on t1.id=t2.key;

How to choose a columns of a select statement based on conditions?

I have to create an SQL Server 2005 query which checks for the value of one attribute in the table and based on its value, select different sets of columns.
How can I do that?
for e.g.
In table 'car', if the values of 'type' attribute are 1 and 2
when type = 1, i want to execute a select 'query1' with 3 columns.
when type = 2, i want to execute another select 'query2' with 4 other columns.
How do I do that?
Please help.
I think you're looking at a Stored Procedure with an If statement. CASE will work, but it can't change the number of columns returned.
SELECT
Col1 = CASE WHEN Type = 1 THEN (SELECT Null FROM T1)
ELSE (SELECT Col1 FROM T2) END
, Col2 = CASE WHEN Type = 1 THEN (SELECT Col1 FROM T1)
ELSE (SELECT Col2 FROM T2) END
, Col3 = CASE WHEN Type = 1 THEN (SELECT Col2 FROM T1)
ELSE (SELECT Col4 FROM T2) END
, Col4 = CASE WHEN Type = 1 THEN (SELECT Col3 FROM T1)
ELSE (SELECT Col4 FROM T2) END
FROM Cars
If you would show us the DDL of all tables involved, you'd probably get a better answer or a different (read better) approach.