Update an existing table using selected records in tsql - sql-server-2008

I am stuck with a query where I need to update an existing table using a dynamically generated record set. I tried searching for the answers but didn't get much help from them.
Here is my query:
with t as
(
SELECT R.Col1, R.Col2, O.Column2, row_number()
OVER (partition by R.Col3, R.Col4
ORDER BY
CASE WHEN #Criteria = 'NA' then R.Col1 END ASC,
CASE WHEN #Criteria = 'ND' then R.Col1 END DESC,
CASE WHEN #Criteria = 'CA' then R.Col2 END ASC,
CASE WHEN #Criteria = 'CD' then R.Col1 END DESC
) as NewOrder
From RecordsTable R innerjoin OtherTable O on R.Col2 = O.Column1
where R.Col3 = #Col5Val
)
Update RecordsTable Set RecordsTable.Ordering = t.NewOrder
where RecordsTable.Name = t.Col1
and RecordsTable.Address = t.Col2
The error I am getting is The multi-part identifier "t.Col1" could not be bound and The multi-part identifier "t.Col2" could not be bound
I am not sure if the query is correct or not, but I guess this should be correct to some extent.
Table Structures
RecordsTable
Col1 | Col2 | Col3 | Col4 | Ordering
------------------------------------------------------------
ABC | 78945 | 8345 | XYZ | 1
OtherTable
Column1 | Column2 | Column3
-----------------------------------
FOO | BAR | 8345
NOTE
The cases are required to sort the records as the NewOrder generated from this is required to update the RecordsTable

You are updating one of the tables involved in your CTE, but you aren't linking it to the CTE during your update. Therefore, you need to join the source table back to the CTE using an inner join in your update statement like so:
--CTE here
Update RecordsTable
Set RecordsTable.Ordering = t.NewOrder
from recordstable r
inner join t on
r.Name = t.Col1 and r.Address = t.Col2
Alternatively, you can include the Name, Address and Ordering columns in your CTE, and directly update the CTE like so:
with t as
(
SELECT R.Col1, R.Col2, O.Column2, R.Name, R.Address, R.Ordering, row_number()
OVER (partition by R.Col3, R.Col4
ORDER BY
CASE WHEN #Criteria = 'NA' then R.Col1 END ASC,
CASE WHEN #Criteria = 'ND' then R.Col1 END DESC,
CASE WHEN #Criteria = 'CA' then R.Col2 END ASC,
CASE WHEN #Criteria = 'CD' then R.Col1 END DESC
) as NewOrder
From RecordsTable R innerjoin OtherTable O on R.Col2 = O.Column1
where R.Col3 = #Col5Val
)
Update t
Set t.Ordering = t.NewOrder
where t.Name = t.Col1
and t.Address = t.Col2
Demo

Related

SQL get MAX datetime in LEFT JOIN

I am running a query against a table and doing a left join to try and get the record from the left table with the most recent date but it's not picking up the other values relevant to the datetime column (user and notes)
SELECT
i.customer_sequence,
i.due_date,
MAX(cn.datetime) as notes_datetime,
cn.user as notes_user,
cn.notes as notes_notes
FROM
billing_invoices i
LEFT JOIN customer_notes cn
ON i.customer_sequence = cn.customer_seq
WHERE
cn.type = 'Accounts' AND
i.customer_sequence <> '0' AND
i.status = 'Unpaid' AND
i.directdebit <> 'Y'
GROUP BY
i.customer_sequence
ORDER BY
i.due_date DESC
Aggregation is not the solution here. You want the entire row from the joined table, so this suggest filtering instead. If you are running MySQL 8.0, I would recommend window functions:
SELECT *
FROM (
SELECT
i.customer_sequence,
i.due_date,
ROW_NUMBER() OVER(PARTITION BY i.customer_sequence ORDER BY cn.datetime DESC) rn,
cn.datetime as notes_datetime,
cn.user as notes_user,
cn.notes as notes_notes
FROM billing_invoices i
LEFT JOIN customer_notes cn
ON i.customer_sequence = cn.customer_seq
AND cn.type = 'Accounts'
WHERE
i.customer_sequence <> '0' AND
i.status = 'Unpaid' AND
i.directdebit <> 'Y'
) t
ORDER BY i.due_date DESC
Note that I moved the condition on the left joined table from the WHERE clause to the ON clause of the join (otherwise, this acts like an inner join).
In earlier versions, one option is a correlated subquery:
SELECT
i.customer_sequence,
i.due_date,
cn.datetime as notes_datetime,
cn.user as notes_user,
cn.notes as notes_notes
FROM billing_invoices i
LEFT JOIN customer_notes cn
ON i.customer_sequence = cn.customer_seq
AND cn.type = 'Accounts'
AND cn.datetime = (
SELECT MAX(cn1.datetime)
FROM customer_notes cn1
WHERE i.customer_sequence = cn1.customer_seq AND cn1.type = 'Accounts'
)
WHERE
i.customer_sequence <> '0' AND
i.status = 'Unpaid' AND
i.directdebit <> 'Y'

Hello Can any one Help me to write this Query in Joins instead of Sub query?

SELECT ST.Id,
ST.Label,
ST.Asset,
CASE
WHEN ST.RFID = '' THEN 'NULL'
ELSE ST.RFID
END AS RFID,
CASE
WHEN ST.Type = 'O' THEN 'Odometer'
ELSE 'Engine Hours'
END AS AccumulatorType,
ST.AppId,
ST.Timestamp,
ST.Accumulator,
CASE
WHEN ST.Flag = 0 THEN 'Disabled'
WHEN ST.Flag = 1 THEN 'Active'
WHEN ST.Flag = 3 THEN 'Rented'
WHEN ST.Flag = 4 THEN 'Bypass'
WHEN ST.Flag = 5 THEN 'Tanker'
END AS TYPE,
(SELECT COUNT(*)
FROM sync
WHERE RowId = ST.Id
AND DefinitionId = 1
AND Status = 1) AS Updated,
(SELECT COUNT(*)
FROM sync
WHERE RowId = ST.Id
AND DefinitionId = 1
AND Status = 0) AS Remaining
FROM SecondaryTags AS ST
WHERE AppId = #AppId
Why do you want to rewrite the logic? Because you have filtering in the outer query, the subquery is likely to be the most performant method for the calculation.
You can speed the subquery by being sure that you have the write indexes. In this case, you want an index on sync(RowId, DefinitionId, StatusId):
create index idx_sync_rowid_definitionid_statusid
on sync(RowId, DefinitionId, StatusId)
You can rewrite the query as:
select . . .,
s.updated, s.remaining
from SecondaryTags st join
(select rowid, sum(status = 1) as updated, sum(status = 0) as remaining
from sync s
where s.definitionId = 1
group by s.rowid
) s
on s.rowid = st.id
where st.AppId = #AppId;
From a performance perspective, though, I think the index is a better idea.
select st.*
, s.updated
, s.remaining
from SecondaryTags st
join (select rowid
, sum(status = 1) as updated
, sum(status = 0) as remaining
from sync s
where s.definitionId = 1
group
by s.rowid
) s
on s.rowid = st.id
where st.AppId = 2;

SQL help on subqueries and table joins

Need some sql help...using MYSQL...I've got some legacy code and a situation to resolve...This code below only returns occupants who have a record in the p_occupants_insurance table. I want to be able to list all the occupants regardless if they have a record in the p_occupants_insurance table or not.
SELECT a.occupants_insurance_id, a.occupant_id, a.policy_nbr, a.policy_type, a.coverage_amount_curr,
CASE
WHEN a.effective_date = '0000-00-00' THEN NULL
ELSE a.effective_date
END as effective_date,
CASE
WHEN a.expiration_date = '0000-00-00' THEN NULL
ELSE a.expiration_date
END as expiration_date,
a.insurance_company, a.custom1_label, a.custom2_label, a.custom3_label, a.custom1, a.custom2, a.custom3, c.name as prop_name, (SELECT x.name FROM portfolio_hierarchy x WHERE x.leaf_node_portf_id = d.portfolio_id ) as p_name, b.name as occupant_name, b.primary_contact, b.phone
FROM p_occupants_insurance a, p_occupants b, properties c, portfolio d
WHERE a.occupant_id = b.occupant_id
AND b.property_id = c.properties_id
AND c.portfolio_id = d.portfolio_id
AND d.account_id = 1
AND b.archived = 0
AND b.trashbin = 0
ORDER BY d.p_name ASC, prop_name ASC, occupant_name ASC, insurance_company ASC, policy_nbr ASC;
I know I can do subqueries like this:
SELECT b.name as occupant_name, b.primary_contact, b.phone,
(SELECT a.occupants_insurance_id FROM p_occupants_insurance a WHERE a.occupants_id = b.occupants_id) as occupants_insurance_id
FROM p_occupants b, properties c, portfolio d
WHERE a.occupant_id = b.occupant_id
AND b.property_id = c.properties_id
AND c.portfolio_id = d.portfolio_id
AND d.account_id = 1
AND b.archived = 0
AND b.trashbin = 0
ORDER BY d.p_name ASC, prop_name ASC, occupant_name ASC, insurance_company ASC, policy_nbr ASC;
But that is going to lead to a subquery for each column I want out of the p_occupants_insurance table. Is there a better way to accomplish this and can you help me write out the SQL? Sorry, SQL is not my strongest point.
Thanks for the help.
Without seeing the schema for each of the tables involved, and relying only on the sample SQL statement, it is difficult to say for sure, but I believe the following will return the result you are looking for:
SELECT
a.`occupants_insurance_id`,
a.`occupant_id`,
a.`policy_nbr`,
a.`policy_type`,
a.`coverage_amount_curr`,
IF(a.`effective_date` = '0000-00-00',NULL,a.`effective_date`) as a.`effective_date`,
IF(a.`expiration_date` = '0000-00-00',NULL,a.`expiration_date`) as a.`expiration_date`,
a.`insurance_company`,
a.`custom1_label`,
a.`custom2_label`,
a.`custom3_label`,
a.`custom1`,
a.`custom2`,
a.`custom3`,
c.`name` as `prop_name`,
(SELECT x.name FROM portfolio_hierarchy x WHERE x.leaf_node_portf_id = d.portfolio_id ) as `p_name`,
b.`name` as `occupant_name`,
b.`primary_contact`,
b.`phone`
FROM `p_occupants` b
LEFT JOIN `p_occupants_insurance` a
ON a.`occupant_id` = b.`occupant_id`
JOIN `properties` c
ON b.`property_id` = c.`properties_id`
JOIN `portfolio` d
ON c.`portfolio_id` = d.`portfolio_id`
WHERE d.account_id = 1
AND b.archived = 0
AND b.trashbin = 0
ORDER BY d.p_name ASC,
`prop_name` ASC,
`occupant_name` ASC,
`insurance_company` ASC,
`policy_nbr` ASC;

Incompatibility with Mysql 5.7(Expression #1 of ORDER BY clause is not in SELECT list)

When I execute the following query I receive an Exception:
Error Code: 3065 Expression #1 of ORDER BY clause is not in SELECT
list, references column 'webstore.level_depth' which is not in
SELECT list; this is incompatible with DISTINCT
My Query:
SELECT DISTINCT c.id_parent, c.id_category, cl.name, cl.description, cl.link_rewrite
FROM `pj_category_shop` cs, `pj_category` c
INNER JOIN `pj_category_lang` cl ON (c.`id_category` = cl.`id_category` AND cl.`id_lang` = 1 AND cl.id_shop = 2 )
WHERE (c.`active` = 1 OR c.`id_category` = 2)
AND cs.`id_category` = c.`id_category`
AND cs.`id_shop` = 2
AND c.`id_category` != 1
AND `level_depth` <= 2
AND c.id_category IN (
SELECT id_category
FROM `pj_category_group`
WHERE `id_group` IN (3)
)
ORDER BY `level_depth` ASC, cl.`name` ASC;
Why is this happening?
I have find the answer for my question.Actually mysql 5.7 contains 'ONLY_FULL_GROUP_BY' in sql mode.So we can't perform orderby in the element that is not in select list.we have to change it from
'ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION'
into
'STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION'
We can done this by executing the following queries
SET SESSION sql_mode = 'STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION'
SET GLOBAL sql_mode = 'STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION'
ORDER BY column should be column listed in the SELECT list
Add c.level_depth in your select list
Try:
SELECT DISTINCT c.id_parent, c.id_category, cl.name, cl.description, cl.link_rewrite, c.level_depth
FROM `pj_category_shop` cs, `pj_category` c
INNER JOIN `pj_category_lang` cl ON (c.`id_category` = cl.`id_category` AND cl.`id_lang` = 1 AND cl.id_shop = 2 )
WHERE (c.`active` = 1 OR c.`id_category` = 2)
AND cs.`id_category` = c.`id_category` AND cs.`id_shop` = 2
AND c.`id_category` != 1
AND `level_depth` <= 2
AND c.id_category IN (SELECT id_category FROM `pj_category_group` WHERE `id_group` IN (3))
ORDER BY c.`level_depth` ASC, cl.`name` ASC;
Sql Feature Order by is as the name suggests used to order the Selected Columns on the basis of the Column mentioned in the below Syntax :
Order by Column_Name ASC/DESC
So if you don't add the column using which you have decided to retrieve order set of data in the select clause you will get this error.
SELECT DISTINCT c.id_parent, c.id_category, cl.name, cl.description, cl.link_rewrite
FROM `pj_category_shop` cs, `pj_category` c
INNER JOIN `pj_category_lang` cl ON (c.`id_category` = cl.`id_category` AND cl.`id_lang` = 1 AND cl.id_shop = 2 )
WHERE (c.`active` = 1 OR c.`id_category` = 2)
ORDER BY c.`level_depth` ASC, cl.`name` ASC
AND cs.`id_category` = c.`id_category` AND cs.`id_shop` = 2
AND c.`id_category` != 1
AND `level_depth` <= 2
AND c.id_category IN (SELECT id_category FROM `pj_category_group` WHERE `id_group` IN (3));
To summarize, you need to have the ORDER BY in the context of the SELECT command, in which case, with the WHERE, FROM and INNER JOIN.
Linking together some threads here - i believe it has to do with mysql version (we were able to bypass by using 5.7) and/or strict mode: https://github.com/publiclab/plots2/pull/8145
Thanks!
There is a way to bypass it. It is not the best practice that you can do ( I think that it is even worse... but if you don't have any control over your SQL_MODE it should work):
SELECT DISTINCT d.id_parent, d.id_category, d.name, d.description, d.link_rewrite
FROM (select c.id_parent, c.id_category, cl.name, cl.description, cl.link_rewrite
FROM `pj_category_shop` cs, `pj_category` c
INNER JOIN `pj_category_lang` cl ON (c.`id_category` = cl.`id_category` AND cl.`id_lang` = 1 AND cl.id_shop = 2 )
WHERE (c.`active` = 1 OR c.`id_category` = 2)
ORDER BY c.`level_depth` ASC, cl.`name` ASC
AND cs.`id_category` = c.`id_category` AND cs.`id_shop` = 2
AND c.`id_category` != 1
AND `level_depth` <= 2
AND c.id_category IN (SELECT id_category FROM `pj_category_group` WHERE `id_group` IN (3))) as d ;

sql server cross join

I have the following query:
select
tt.ItemOrder, tt.DisplayVal as Task, tt.Responsible as ResParty,
tt.DaysDue,
ActualDate = (select convert(varchar(10), cnfmdate, 101) from ProSer where PId = #PID), PDate = #PDate
from
tblTimeline tt
where
tt.ID = 1
What I need to do is to put it in a view such that I can call the view simply using the PID.
I came up with the following and used the cross join:
create view view1 as
select
ps.PID, tt.ID, tt.ItemOrder, tt.DisplayVal as Task,
tt.Responsible as ResParty, tt.DaysDue,
ps.cnfmdate As ActualDate, ProgStartDate as ProgramDate
from
tblTimeline tt
cross join
ProSer ps
where
tt.ID = 1 and ps.cancelled = 0
Notice now, I can do the following
select *
from view1
where PID = '34343'
and then I can retrieve it from the view.
Now, I am not sure how to do similiarly with the following in which case I need to put it in a cross join similarly to how I did above.
Notice how actual date is somehat more involved. I need to use the cross table similarly to how I did it above but not as you can see, it is somewhat more involved.
(notice for this part, I will simly join to the view1 that I have above with UNION
select
tt.ItemOrder, tt.DisplayVal as Task, tt.Responsible as ResParty,
ActualDate = (
CASE
WHEN
NOT EXISTS(SELECT * FROM Spls WHERE RequestRcvd = 1 AND PID = #PID)
THEN
'N/A'
WHEN EXISTS (SELECT * FROM spls WHERE RequestRcvd = 1 AND RequestRcvdDate IS NOT NULL)
THEN
(SELECT CONVERT(VARCHAR(10),MAX(RequestRcvdDate),101) from spls WHERE RequestRcvd = 1 AND PID = #PID)
END
)
from
tblTimeline tt
where
tt.ID = 9
I need to know how I can create this in a cross join (which will be inside of a view) such that I can do the following similarly to how I did the above one
select *
from view1
where PID = '34343'
and then I can retrieve it from the view.
There might be a way to simplify the query, but the following should work:
select p.pid, tt.ItemOrder, tt.DisplayVal as Task,
tt.Responsible as ResParty,
ActualDate = (CASE WHEN NOT EXISTS(SELECT * FROM Spls WHERE RequestRcvd = 1 AND spls.PID = p.PID)
THEN 'N/A'
WHEN EXISTS (SELECT * FROM spls WHERE RequestRcvd = 1 AND RequestRcvdDate IS NOT NULL)
THEN (SELECT CONVERT(VARCHAR(10),MAX(RequestRcvdDate),101) from spls WHERE RequestRcvd = 1 AND spls.PID = p.PID)
END)
from tblTimeline tt cross join
poser p
where tt.ID = 9
All I did was add the cross join to poser and replace #PID with p.pid. The results is a subquery that contains a reference to a table at an outer level. Such a subquery is called a correlated subquery.