SQL select column equivalence - sql

I have a table that saves the possible states of other tables (entities).
But now I need to find equivalence of states between two entities.
The table structure is something like this
ID TableID StateValue StateDefinition StateDescription
================================================================
1 1 1 Created Just created
2 1 2 Dropped Just Dropped
3 2 1 Created Just Created
4 2 2 Aproved Passed the revision
5 2 3 Dropped Just dropped
I want to get equivalent (comparing text of state) which as a result get this:
TableID1 StateValue1 TableID2 StateValue2 StateDefinition
=============================================================================
1 1 2 1 Created
1 2 2 3 Dropped
My question is, how can it be done??

Do a self join on the table.
A general case might look like:
SELECT A.TableID as TableId1,
A.StateValue as StateValue1,
B.TableId as TableId2,
B.StateValue as StateValue2,
A.StateDefinition
FROM
Table A
INNER JOIN Table B
ON (A.TableId <> B.TableId and A.StateDefiniton = B.StateDefinition)

select t1.TableID as TableID1,
t1.StateValue as StateValue1,
t2.TableID as TableID2,
t2.StateValue as StateValue2,
t1.StateDefinition
from MyTable t1
inner join MyTable t2 on t1.TableID = 1 and t2.TableID = 2
where t1.StateValue = t2.StateValue
and t1.StateDefinition = t2.StateDefinition

Related

case when results as left join condition

Table 1
Staff category hours cost
1 Cleaning 5 20
1 Scrubbing 6 30
1 Cleaning 8 40
2 Scrubbing 4 30
table 2
`
Staff type vendor category
1 part A Cleaning
1 full b Cleaning
1 full c Scrubbing
...’
To join these two tables I added a new col “type”:
Case when table1.hours=8
Then ”full”
Else ”part”
End as “type”
From table1
Left join table2 on type=table2.type
And Table 1.staff =table2.staff
And Table1.category=table 2.category
My desired outcome is
Staff category Cost vendor type
1 Cleaning 20 A. Part
1 Cleaning 40 B. Full
1 Scrubbing 30 C. Part
However the type=table2.type condition didn’t work so it became
Staff category Cost vendor type
1 Cleaning 20 A. Part
1 Cleaning 20 B. part
1 cleaning 40. A Full
1. Cleaning 40 B. Full
Below is for BigQuery Standard SQL
#standardSQL
SELECT staff, category, cost, vendor, type
FROM (
SELECT *, IF(hours = 8, 'full', 'part') AS type
FROM `project.dataset.table1`
) t1
LEFT JOIN `project.dataset.table2` t2
USING (type, staff, category)
If I have not understood, you want an implementation that creates a column in table1 and then joins with table2 on the condition table1.category = table2.category and table1.type = table2.type. If that's the case you could try with the following:
SELECT t1.Staff, t1.category, t1.cost, table2.vendor, t1.type
FROM (
SELECT *, CASE WHEN table1.hours = 8 THEN "full" ELSE "part" END as type
FROM table1
) t1
INNER JOIN table2
ON t1.category = table2.category
AND t1.type = table2.type
AND t1.staff = table2.staff

SQL Server update and replace values with values from another table

I have two tables:
Connections:
id user_id connection_info
------------------------------
1 1 ...
2 1 ...
3 2 ...
Lists:
id connection_id name
-----------------------
1 1 ...
2 2 ...
3 1 ...
I currently have user_id's in the lists.connection_id column. I would like to join the lists table with the connections table by connections.user_id = lists.connection_id and then replace the lists.connection_id with the corresponding id from the connections table.
You could use UPDATE FROM like this:
update l
set l.connection_id = c.id
from connections c join lists l on c.user_id = l.connection_id
Initially you would want to test what you are going to update, running a SELECT statement:
select l.connection_id as con_old
, c.id as con_new
, ... (other cols you might want to check)
from connections c join lists l on c.user_id = l.connection_id

Update a range of rows in a table where the condition is in another table

example:
table 1
invoice line article price
1 1 pen 10
1 2 mouse 11
1 3 paper 15
2 1 ... 25
2 2 ... 80
2 3 ...
2 4 ....
table 2
invoice date
1 2014-01-03 00:00:00.0000
2 2014-05-12 00:00:00.0000
3 2014-06-17 00:00:00.0000
how can I update the price only on the rows where the invoice date is for example the month of november
I know that i must use a join but i'm already joining this table for doing other stuff in the same query:
UPDATE invoicelines
SET invoicelines.netprice = ART.price
FROM invoicelines IL INNER JOIN items ITM
ON IL.item = ITM.item
i want to update the invoicelines with a specified date, but this date is in another table, and the situation is similar to the first example
update table1
set price = price + 10
from table1 t1 join table2 t2 on t1.invoice = t2.invoice
where month(t2.date) = 11
As to "I know that i must use a join": No, you don't have to join. When a condition is in another table you would usually use EXISTS or IN.
update table1
set price = ...
where invoice in
(
select invoice
from table2
where month(`date`) = 11
);
Or:
update table1
set price = ...
where exists
(
select *
from table2
where month(table2.`date`) = 11
and table2.invoice = table1.invoice
);
You forgot to name your dbms. Date functions are mostly dbms specific, so a MONTH function may be available or not.
I Solved With This
UPDATE Invoicelines
SET Invoicelines.NetPrice = ART.Price
FROM Invoicelines BR INNER JOIN Items ART join InvoiceHead bt on month(bt.docdate)=11
ON BR.Item = ART.Item
where BR.sheetNumber=bt.sheetNumber

Query for matching multiple rows?

We have next tables in our system
Table object
object_id object_description
1 "Car"
2 "Person"
Table attribute
attribute_id attribute_name
1 "hair_color"
2 "height"
3 "number_of_doors"
4 "engine_size"
Table attribute_value
attribute_id attribute_value_id value
1 1 "black"
1 2 "blonde"
2 1 "more than 1 meter"
2 2 "less than 1 meter"
3 1 "5 doors"
3 2 "3 doors"
4 1 "more than 1.9"
4 2 "less than 1.9"
Table object_attribute
object_id attribute_id attribute_value_id
1 3 1 -- Car, number of doors,5
1 3 2 -- Car, number of doors,2
1 4 1 -- Car, engine size, greater than 1.9
1 4 2 -- Car, engine size, less than 1.9
With this structure we are having a lot of problems getting objects that match multiple criterias (i.e. get all cars with 3 doors and engine size bigger than 1.9)
Currently we are using INTERSECTS for doing this
SELECT OBJECT_ID
FROM object_attribute
WHERE attribute_id = 3
AND attribute_value = 2
INTERSECT
SELECT OBJECT_ID
FROM object_attribute
WHERE attribute_id = 4
AND attribute_value = 1
There are diferent objects with diferent number of attributes, so we can't use a fixed number of JOINs or INTERSECTs anymore
Is there any way of generate multiple combinations of all attributes in a "dynamic way"?
What we would like to achieve is a dynamic query that builds a view like this:
object_id | att_name_1 | att_value_1 | att_name_2 | att_value2 | att_name_n | attr_value_n
As the number of attributes is variable we should trigered and update of the query when a new object is inserted
Guys I think what I have in mind is not possible, so we will probably go with this dynamic query construction at runtime. Thank you all for your answers
after some tests i came up with the following query:
select distinct
a.attribute_name, o.object_description, av.value,
oa.attribute_id, oa.object_id, oa.attribute_value_id
from object_attribute oa
inner join attribute a on (oa.attribute_id = a.attribute_id and a.attribute_id = 3)
inner join object o on (oa.object_id = o.object_id and o.object_id = 1)
inner join attribute_value av on (oa.attribute_value_id = av.attribute_value_id and av.attribute_value_id = 2)
where
(av.attribute_id = 3 and o.object_id = 1 and av.attribute_value_id = 2)
union
select distinct
a.attribute_name, o.object_description, av.value,
oa.attribute_id, oa.object_id, oa.attribute_value_id
from object_attribute oa
inner join attribute a on (oa.attribute_id = a.attribute_id and a.attribute_id = 4)
inner join object o on (oa.object_id = o.object_id and o.object_id = 1)
inner join attribute_value av on (oa.attribute_value_id = av.attribute_value_id and av.attribute_value_id = 1)
where
(av.attribute_id = 4 and o.object_id = 1 and av.attribute_value_id = 1)
which results in the following:
If you are using MS SQL Server I would put it in a stored procedure that accepts the three Id's as parameters.

SQL join to table with 3 possible cases: table can have no records, match 1 or more, records or require all records found to match

I have a 2 tables:
Questions table with Question ID
Part Table:
Question ID
Part ID
BAllPartsRequired
The user will select some parts (or may select none) and depending on what was selected certain questions will be displayed.
I want to join the 2 tables for 3 scenerios but do them all in 1 query. I can write each scenerio individually (EDIT I thought I could but scenario 3 I can not get to work where it requires all found in part table to be selected) but can not figure out how to get them all in 1 query (I have done something similar before but cant remember how).
If no parts exist in part table for that question retruen the question
If any part selected exists in part table return question (i.e. user selects 1 part and 5 parts are associated to that question then the question will match and be returned). BAllPartsRequired = false
If user selects parts and ALL of the parts are associated to the question the question is returend but if NOT all parts are selected by user the question is not returend (i.e. user selects 3 parts and there are 4 parts in table then the user will not see the question, but if the user selectes all 4 parts the question will be shown). BAllPartsRequired = true
I am an advanced SQL programmer but this is eluding me and I know I have done this before but how do I get it to work in 1 query, do I do a nested join, a left join, a case on the where statement or something else.
Sample Data:
Question Form Association:
NFormAssociationID NQuestionID FormType
1 1 PAEdit
2 2 PAEdit
3 3 PAEdit
4 4 PAEdit
Question Part Form Association Table:
ID NFormAssociationID PartNumber BAllPartsRequired
1 1 1 0
2 2 2 1
3 2 3 1
Query without the new parts table added:
Select ROW_NUMBER() OVER(ORDER BY QL.NOrderBy) AS RowNumber,
QL.NQuestionID, QL.FieldName, QL.Question, QL.BRequired, QFL.FormFieldType, QFL.SingleMultipleSM,
QFL.CSSStyle
FROM dbo.QuestionFormAssociation QA WITH (NOLOCK)
INNER JOIN dbo.QuestionLookup QL WITH (NOLOCK) ON QA.NQuestionID = QL.NQuestionID
INNER JOIN dbo.QuestionFieldTypeLookup QFL WITH (NOLOCK) ON QL.NFieldTypeID = QFL.NFieldTypeID
WHERE QA.BActive = 1 AND QL.BActive = 1 AND QFL.BActive=1
AND QA.FormType = 'PAEdit'
ORDER BY QL.NOrderBy
Simple query using new table
Select ID
FROM dbo.QuestionPartFormAssociation
WHERE BAllPartsRequired = 1
AND PartNumber IN ('1', '2') --'1', '2', '3')
It sounds like you are trying to find the eligible questions, based on some criteria.
In this sitatuion, it is best to summarize first at the question level, and then apply logic to those summaries. Here is an example:
select q.questionid
from (select q.questionid,
max(case when qp.questionid is null then 1 else 0 end) as HasNoParts,
sum(case when qp.partid in (<user parts>) then 1 else 0 end) as NumUserParts,
count(qp.questionid) as NumParts,
max(qp.AllPartsRequired) as AreAllPartsRequired
from question q left outer join
questionpart qp
on q.questionid = qp.questionid
group by q.questionid
) q
where HasNoParts = 1 or -- condition 1
AreAllPartsRequired = 0 and NumUserParts > 0 or -- condition 2
AreAllPartsRequired = 1 and NmUserParts = NumParts -- condition 3
I've simplified the table and column names to make the logic clearer.
updated with full answer from OP:
Select ROW_NUMBER() OVER(ORDER BY QL.NOrderBy) AS RowNumber,
QL.NQuestionID, QL.FieldName, QL.Question, QL.BRequired, QFL.FormFieldType, QFL.SingleMultipleSM,
QFL.CSSStyle
FROM dbo.QuestionFormAssociation QA WITH (NOLOCK)
INNER JOIN dbo.QuestionLookup QL WITH (NOLOCK) ON QA.NQuestionID = QL.NQuestionID
INNER JOIN dbo.QuestionFieldTypeLookup QFL WITH (NOLOCK) ON QL.NFieldTypeID = QFL.NFieldTypeID
INNER JOIN (
select q.NFormAssociationID,
max(case when qp.NFormAssociationID is null then 1 else 0 end) as HasNoParts,
sum(case when qp.PartNumber in ('1','2','3') then 1 else 0 end) as NumUserParts,
count(qp.NFormAssociationID) as NumParts,
qp.BAllPartsRequired
from QuestionFormAssociation q
left outer join QuestionPartFormAssociation qp on q.NFormAssociationID = qp.NFormAssociationID
AND QP.BActive = 1
WHERE Q.FormType = 'PAEdit'
AND Q.BActive = 1
group by q.NFormAssociationID, qp.BAllPartsRequired
) QSUB ON QA.NFormAssociationID = QSUB.NFormAssociationID
WHERE QA.BActive = 1 AND QL.BActive = 1 AND QFL.BActive=1
AND (
QSUB.HasNoParts = 1 -- condition 1
OR (QSUB.BAllPartsRequired = 0 and QSUB.NumUserParts > 0) -- condition 2
OR (QSUB.BAllPartsRequired = 1 and QSUB.NumUserParts = QSUB.NumParts) -- condition 3
)
ORDER BY QL.NOrderBy