First time here so I didn't see a question like this so I hope you can help me.
I am attempting to add 2 columns to a query result.
If aa.actionid = '123', return a result in a column called test1.
Ifaa.actionid = '5', then create a column called this to put the price per ton in that column called either test 1 or test 2
This is what I have so far. I am not really sure if this is right:
SELECT CO.INVOICE_PREFIX
,C.CUSTOMER_NAME
,S.SITE_NAME
,W.DESCRIPTION
,AA.PER_TON_PRICE
,AA.ACTION_ID
,AA.APPLICABLE_ACTION_ID
,OI.VALID_UNTIL
,CON.END_DATE
,CC.DESCRIPTION
,(case when aa.actionid = '123' then aa.per_ton_price Test1
,(case when aa.actionid = '5' then) aa.per_ton_price test2
FROM CUSTOMER C
JOIN SITE S ON C.CUSTOMER_ID = S.CUSTOMER_ID
JOIN CONTRACT CON ON C.CUSTOMER_ID = CON.CUSTOMER_ID
JOIN SITE_ORDER SO ON SO.SITE_ID = S.SITE_ID
JOIN COMPANY_OUTLET CO ON SO.COMPANY_OUTLET_ID = CO.COMPANY_OUTLET_ID
JOIN ORDER_ITEM OI ON OI.ORDER_ID = SO.SITE_ORDER_ID
JOIN PRODUCT P ON OI.PRODUCT_ID = P.PRODUCT_ID
JOIN APPLICABLE_ACTION AA ON AA.ORDER_ITEM_ID = OI.ORDER_ITEM_ID
JOIN COMPETITIVE_CONDITION CC ON CC.COMPETITIVE_CONDITION_ID = OI.COMPETITIVE_CONDITION_ID
LEFT JOIN WASTE W ON W.WASTE_ID = AA.WASTE_ID
JOIN ACTION A ON AA.ACTION_ID = A.ACTION_ID
WHERE AA.ACTION_ID IN ('123','5')
AND P.PRODUCT_ID='2'
AND OI.VALID_UNTIL >= GETDATE()
You will always need to return both columns for all rows. What you can do is map the 'unused' column (dependent on the row data) to a default value, such as null, e.g.:
,case when aa.actionid = '123' then aa.per_ton_price else null end Test1
,case when aa.actionid = '5' then aa.per_ton_price else null end test2
The database is only going to return a TABLE, so if you think about the concept of a Table, could one row have different amount of columns than the others? Probably not. So what you really want to be doing is set the particular column's value to null instead of trying to not output that column at all.
Related
I want to get fields from 2 different tables . The last field candidate_score_id has a many to one relationship. So how should I join the below 2 queries
1) To get candidate_score_id from the candidate_score table.
select candidate_score_id from candidate_score a where
a.assessment_id = NEW.assessment_id and
a.candidate_id = NEW.candidate_id and
a.attempt_Count = NEW.attempt_count;
2) To insert different fields in to the candidate_score_details table. The field in this table should be obtained by query above.
insert into candidate_score_details(candidate_score_details_id, candidate_id, assessment_id, attempt_count, score_type, score_tag,correct, candidate_score_id)
select uuid();
select a.candidate_id, a.assessment_id,a.attempt_count,"BY-COMPLEXITY",
case c.complexity
when 1 then "HIGH"
when 2 then "MEDIUM"
when 3 then "LOW"
end, count(*) from candidate_answer a, answer_key b, question_meta_data c where a.candidate_id = NEW.candidate_id and
a.assessment_id = NEW.assessment_id and
a.attempt_count = NEW.attempt_count and
a.assessment_id = b.assessment_id and
a.question_id = b.question_number and
a.response = b.answer and
a.question_id = c.question_number
group by a.candidate_id, a.assessment_id, a.attempt_count, c.complexity;
Just looking at the SQL joining aspect of your question, you'll need to specify the table I THINK you're aliasing a 2nd table with the "NEW" reference. If that's the case, then the query would be (replacing "OTHER_TABLE_NAME" with the name of the 2nd table:
select a.candidate_score_id
from candidate_score a
left join OTHER_TABLE_NAME new on
and a.assessment_id = NEW.assessment_id
and a.candidate_id = NEW.candidate_id
and a.attempt_Count = NEW.attempt_count
Seems that Query 1 has the same 3 criteria on the "candidate_score" table as for the "candidate_answer" table in Query 2.
So how about adding a LEFT JOIN of "candidate_score" to "candidate_answer" on those 3 fields?
For example:
INSERT INTO candidate_score_details
(
candidate_score_details_id,
candidate_id,
assessment_id,
attempt_count,
score_type,
score_tag,
correct,
candidate_score_id
)
SELECT
uuid(),
answer.candidate_id,
answer.assessment_id,
answer.attempt_count,
'BY-COMPLEXITY' AS score_type,
(CASE meta.complexity
WHEN 1 THEN 'HIGH'
WHEN 2 THEN 'MEDIUM'
WHEN 3 THEN 'LOW'
END) AS score_tag,
COUNT(*) AS correct,
MAX(score.candidate_score_id) AS max_candidate_score_id
FROM candidate_answer AS answer
JOIN answer_key AS akey
ON (akey.assessment_id = answer.assessment_id AND akey.question_number = answer.question_id AND akey.answer = answer.response)
LEFT JOIN candidate_score AS score
ON (score.candidate_id = answer.candidate_id AND score.assessment_id = answer.assessment_id AND score.attempt_count = answer.attempt_count)
LEFT JOIN question_meta_data AS meta
ON meta.question_number = answer.question_id
WHERE answer.candidate_id = NEW.candidate_id
AND answer.assessment_id = NEW.assessment_id
AND answer.attempt_count = NEW.attempt_count
GROUP BY answer.candidate_id, answer.assessment_id, answer.attempt_count, meta.complexity;
The code :
UPDATE tt_t_documents
SET t_Doc_header_ID = (SELECT
MIN(dh.Doc_header_ID)
FROM tt_t_documents td WITH (NOLOCK)
JOIN Doc_header dh WITH (NOLOCK)
ON dh.DH_doc_number = td.t_dh_doc_number
AND dh.DH_sub = 1
JOIN Pred_entry pe WITH (NOLOCK)
ON pe.Pred_entry_ID = dh.DH_pred_entry
JOIN Doc_type dt WITH (NOLOCK)
ON dty.Doc_type_ID = pe.PD_doc_type
AND dt.DT_mode = 5
HAVING COUNT(dh.Doc_header_ID) = 1);
I want to update my columns, but before that I also want to check if there is only one ID found.
The problem in this select is that I get more than one ID.
How can I write a query that updates each row and checks in the same query that there is only one id found?
I am guessing that you intend something like this:
update td
set t_Doc_header_ID = min_Doc_header_ID
from tt_t_documents td join
(select DH_doc_number, min(dh.Doc_header_ID) as min_Doc_header_ID
from Doc_header dh join
Pred_entry pe
on pe.Pred_entry_ID = dh.DH_pred_entry join
Doc_type dt
on dty.Doc_type_ID = pe.PD_doc_type and dt.DT_mode = 5
where dh.DH_doc_number = td.t_dh_doc_number and dh.DH_sub = 1
group by DH_doc_number
having count(dh.Doc_header_ID) = 1
) dh
on dh.DH_doc_number = td.t_dh_doc_number;
Using a join also means that you do not update the values where the condition does not match. If you use a left join, then the values will be updated to NULL (if that is your intention).
I'm not sure I believe you are getting more than one id back with that select given that you are doing a 'min' on it and have no group by. It should be only returning the lowest value for Doc_header_id.
To do what you are asking, first, you should have some way of joining to the tt_t_documents table in the update statement (eg. where td.id == tt_t_documents.id).
Second, you could re-write it to use the sub-query in the from. Something like:
update
tt_t_documents
set
t_Doc_header_ID = x.Doc_Header_id
from tt_t_documents join (
select td.id,
min(dh.Doc_header_ID)
from
tt_t_documents td
join Doc_header dh
on dh.DH_doc_number = td.t_dh_doc_number
and dh.DH_sub = 1
join Pred_entry pe
on pe.Pred_entry_ID = dh.DH_pred_entry
join Doc_type dt
on dty.Doc_type_ID = pe.PD_doc_type
and dt.DT_mode = 5
group by td.id
having
count(dh.Doc_header_ID) = 1
) x on tt_t_documents.id= x.id;
The syntax may not be perfect and I'm not sure how you want to find the doc_header_id but it would be something like this. The sub query would only return values with 1 doc_header_id). Not knowing the schema of your tables, this is as close as I can get.
I have a cs cart database and I am trying to select all the attributes for all the products, the problem is that for each separate attribute for a product, my query creates a new row, I want to to have a single row for each products that has all the attributes into columns.
This is my query right now:
SELECT a.product_id, b.variant, c.description, d.product_code
FROM cscart_product_features_values a
LEFT JOIN cscart_product_feature_variant_descriptions b ON a.variant_id = b.variant_id
LEFT JOIN cscart_product_features_descriptions c ON a.feature_id = c.feature_id
LEFT JOIN cscart_products d ON a.product_id = d.product_id
After I run the query, I get the following result:
product_id;"variant";"description";"product_code"
38;"1st";"Grade Level";"750"
38;"Math";"Subject Area";"750"
38;"Evan-Moor";"Publisher";"750"
etc next product
What I want is this:
product_id;"product_code";"Grade Level";"Subject Area";"Publisher"
38;"750";"1st";"Math";"Evan-Moor"
etc next product
We only have 3 type of attributes: Grade Level, Subject Area and Publisher.
Any ideas how to improve my query and achieve this? I would be happy even with concatenating all 3 attributes in one column, delimited by ",".
This is a generic SQL solution using GROUP BY and MAX(case expression) to achieve the transformation of 3 rows into a single row with the 3 columns.
SELECT
v.product_id
, p.product_code
, MAX(CASE WHEN fd.description = 'Grade Level' THEN vd.variant END) AS GradeLevel
, MAX(CASE WHEN fd.description = 'Subject Area' THEN vd.variant END) AS SubjectArea
, MAX(CASE WHEN fd.description = 'Publisher' THEN vd.variant END) AS Publisher
FROM cscart_products p
LEFT JOIN cscart_product_features_values v ON p.product_id = v.product_id
LEFT JOIN cscart_product_feature_variant_descriptions vd ON v.variant_id = vd.variant_id
LEFT JOIN cscart_product_features_descriptions fd ON v.feature_id = fd.feature_id
GROUP BY
v.product_id
, p.product_code
This approach should work on just about any SQL database.
Note also that I have changed the order of tables because I presume there has to be a row in cscart_products, but there might not be related rows in the other tables.
I have also changed the aliases, personally I do not care for aliaes based on the order of use in a query (e.g. I just changed the order so I had to change all references). I have use 'p' = product, 'v' = variant, 'vd' = variant description & 'fd' = feature description' - with such a convention for aliases I can re-arrange the query without changing every reference.
I'm trying to perform what I believe a very simple case-update SQL to two different column based on a select:
PROD_TB:
Product_Code Reg_Price Sale_Price
A 1000 2000
PRICE_TB:
Product_Code Type Price
A REG 3000
A SALE 4000
Desired update result:
PROD_TB:
Product_Code Reg_Price Sale_Price
A 3000 4000
What I attempted:
UPDATE PROD_TB
SET Reg_Price = CASE
WHEN PRICE_TB.Type = 'REG'
THEN PRICE_TB.Price
ELSE Reg_Price
END,
Sale_Price = CASE
WHEN PRICE_TB.Type = 'SALE'
THEN PRICE_TB.Price
ELSE Sale_Price
END
FROM
PROD_TB
JOIN
PRICE_TB ON PROD_TB.PRODUCT_CODE = PRICE_TB.PRODUCT_CODE
Running the above SQL only updates regular price, not the sale price. Does SQL not support these types of update query? Or did I make an elementary mistake?
Something like this? Basically, just join the set from the PRICE_TB on the condition of which column you want to get from it.
But this is assuming you will only ever have one PRICE_TB.TYPE per updated PROD_TB column name, and that each PROD_TB column always contains a value in PRICE_TB, otherwise it'll be NULL and that row won't be returned. So make sure you know the variations of data that can exist here.
UPDATE PROD
SET Reg_Price = REG.Price, Sale_Price = SALE.Price
FROM PROD_TB PROD
JOIN PRICE_TB REG ON REG.Product_Code = PROD.Product_Code AND REG.Type = 'REG'
JOIN PRICE_TB SALE ON SALE.Product_Code = PROD.Product_Code AND SALE.Type = 'SALE'
You need to get the data into one row first, here's example that fetches always the biggest price, in case there's more than one in PRICE_TB, otherwise it should work the same way as #Kahn's sql.
UPDATE
PROD
SET
PROD.Reg_Price = PRICE.Reg_Price,
PROD.Sales_Price = PRICE.Sales_Price
FROM PROD_TB PROD, cross apply (
select
max(CASE WHEN Type = 'REG' THEN Price ELSE 0 end) as Reg_Price,
max(CASE WHEN Type = 'SALE' THEN Price ELSE 0 end) as Sale_Price
from
PRICE_TB PRICE
where
PRICE.Product_Code = PROD.Product_Code
) PRICE
If your table PRICE_TB doesn't always contain both values, you could use this to make sure the table is updated anyway:
UPDATE t1
SET
Reg_Price = coalesce(t2.Price, t1.Reg_Price),
Sale_Price = coalesce(t3.Price, t1.Sale_Price)
FROM PROD_TB t1
LEFT JOIN
PRICE_TB t2
ON
t1.ProductCode = t2.ProductCode AND
t2.[Type] = 'REG'
LEFT JOIN
PRICE_TB t3
ON
t1.ProductCode = t3.ProductCode AND
t3.[Type] = 'SALE'
WHERE
t2.[Type] = 'REG' OR
t3.[Type] = 'SALE'
select
tmp.templatedesc Template
,sec.name Section
,q.questiontext Questions,
--,sum(case when q.responserequired = '0' then 1 else null end) as 'N/A'
--,sum(case when q.responserequired = '1' then 1 else null end) as Scored
--,count (case when (qr.weightedscore is not null and tmp.templatedesc = 'QA 30 Day Call Form' and
--sec.name = 'opening' and
--rv.reviewstatusid = 1 )then 1 else null end) as scored
----,(case when qr.weightedscore <> q.weight then rv.reviewid else null end) as fail
--count (case when qr.weightedscore is null then 1 else null end) NA,
--count (case when qr.weightedscore is not null then 1 else null end) scored,
sec.sequencenumber, q.questionnumber, qr.*
from
aqm.dbo.reviewtemplate tmp (nolock)
inner join aqm.dbo.section sec on sec.templateid =tmp.templateid
inner join aqm.dbo.sectionresult scr on scr.sectionid = sec.sectionid
inner join aqm.dbo.questionresult qr on qr.sectionresultid = scr.sectionresultid
inner join aqm.dbo.question q on q.questionid = qr.questionid
--inner join aqm.dbo.questiontype qt on qt.questiontypeid = q.questiontypeid
--left outer join aqm.dbo.questionoption qo on qo.questionid = q.questionid
inner join aqm.dbo.review rv on tmp.templateid = rv.templateid
inner join aqm.dbo.media md on md.mediaid = rv.mediaid
inner join aqm.dbo.iqmuser ut on md.userid = ut.userid
where
rv.reviewstatusid = 1 and
tmp.templatedesc = 'QA 30 Day Call Form'
and sec.name = 'opening' and
convert(varchar,dateadd(hh,-7,rv.reviewdate), 101) = '07/07/2014'
and ut.windowslogonaccount = 'name.name'
and q.questionnumber = 4
--group by
--tmp.templatedesc , sec.name, q.questiontext, sec.sequencenumber, q.questionnumber
order by
sec.sequencenumber, q.questionnumber
the questionresultid and sectionresultid are returning multiple values
how can i fix the joins so that it doesnt return multiple values?
i have it drilled down to a date and a person so that it should only return one row of results( but that obviously didnt work)
not sure what other data i can provide
update
i think it has to do with joins
inner join aqm.dbo.sectionresult scr on scr.sectionid = sec.sectionid
inner join aqm.dbo.questionresult qr on qr.sectionresultid = scr.sectionresultid
as those are the ones returning multiple results.
just dont know how to fix it
First, neither aqm.dbo.questiontype nor aqm.dbo.questionoption are used in your return fields or your where clause so get rid of them if they aren't required.
Second, you are OUTER JOINing on the aqm.dbo.review, but the reviewstatusid and reviewdate are required in the WHERE clause - so this should probably be an INNER JOIN.
Last, best way to debug issues like this is to comment out the COUNT statements and the GROUP BY clause - and see what raw data is being returned.