Updating table cells until reaching a predefined total - sql

I'm trying to solve a question via SQL ...
Let's suppose this is my table:
NAME | ITEM1 | ITEM2 | ITEM3
AAA 1 2 1
BBB 2 1 3
CCC 3 2 1
DDD 3 1 2
EEE 1 3 1
Now, 1 and 2 are the values I have to keep stored in. The 3 value is the one I have to modify in every column ...now, this value must be changed to 1 until reaching a defined total, else it must be changed to 2.
For example : in the ITEM1 column, let's suppose I need to have three times the value 1. It means I should modify one of the two 3 present values with 1 (It doesn't matter which) and the other one with 2. And so on for all the remaining columns ...
Could you please help me finding a quick way to do this?

I dont know if this will work for your case, but it does what you want. The problem is size of the query (2 updates for each column).
obs. #teste is your table
declare #max_number_1_per_column int = 3
declare #coun_1 int
--assuming that you need to update all columns with the same rule (max number 1 in each column is 3, in this example)
--assuming name is unique
select #coun_1 = count(*) from #teste where item1 = 1
if (#max_number_1_per_column - #coun_1 > 0)
update #teste
set item1 = 1
where name in (select top(#max_number_1_per_column - #coun_1) name from #teste where item1 = 3)
update #teste
set item1 = 2
where item1 = 3
---other column
select #coun_1 = count(*) from #teste where item2 = 1
if (#max_number_1_per_column - #coun_1 > 0)
update #teste
set item2 = 1
where name in (select top(#max_number_1_per_column - #coun_1) name from #teste where item2 = 3)
update #teste
set item2 = 2
where item2 = 3
---other column
select #coun_1 = count(*) from #teste where item3 = 1
if (#max_number_1_per_column - #coun_1 > 0)
update #teste
set item3 = 1
where name in (select top(#max_number_1_per_column - #coun_1) name from #teste where item3 = 3)
update #teste
set item3 = 2
where item3 = 3

Related

How do use SQL scripts in R

I need to write a SQL query
Here are my tables
x <- read.csv("C:/Users/Admin/Downloads/Set 1-1.csv",sep=",",dec=".")
y <- read.csv("C:/Users/Admin/Downloads/Set 1-2 - Copy.csv",sep=",",dec=".")
y$score <- 1
I tried joining it
library("sqldf")
select clientid,emailmessageid,null cnttrn,idatediff,null score from x
union all select clientid,emailmessageid,cnttrn,idatediff,score from y
But I get the following errors:
select clientid,emailmessageid,null cnttrn,idatediff,null score from x
Error: unexpected symbol in "select clientid"
union all select
clientid,emailmessageid,cnttrn,idatediff,score from y
Error:
unexpected symbol in "union all"
Please help to correct it. Thank you.
dput(x)
ClientID EmailMessageId MinDate MaxDate IdSlip WwsCreatedDate ProductArticle ProductGroupName MainProductGroupName CategoryGroupName QtytItems SumAmount iDateDiff
3E34C0C9FC05975CC0F01D7A3DEE73D022538FA04B17A0316178E090C04F84A8 894DB62F7B7A6ED2 31.08.2016 31.08.2016 4A19280A1164CF3F4A701EF9AE97A1F1084B611000B94C02 24.09.2015 item1 item2 item3 item4 1 580.0 -342
3E34C0C9FC05975CC0F01D7A3DEE73D022538FA04B17A0316178E090C04F84A8 894DB62F7B7A6ED2 31.08.2016 31.08.2016 4A19280A1164CF3F4A701EF9AE97A1F1084B611000B94C02 24.09.2015 item1 item2 item3 item4 1 3190.0 -342
dput(y)
ClientID EmailMessageId CntTrn iDateDiff score
86139F31664463A8B7592B6887B731A9FC2C3489BB1756A5BF334CFDEA4EF604 9EDCC1391C208BA0 1 4 1
BD483D69913E3EBFE5FBA87A1FFAB7DCD061055FFB4342C2F27AC01F36833254 EF72D53990BC4805 1 5 1
0B3B2F06C3033B3AFD83BA59B405BCC79BC69801FD3B69931F117B8D754A80EB 9EDCC1391C208BA0 1 3 1
This runs without errors for me. The only difference is that the query is formatted. Is the result correct?
library(sqldf)
y <- read.table(text = "ClientID EmailMessageId CntTrn iDateDiff score
86139F31664463A8B7592B6887B731A9FC2C3489BB1756A5BF334CFDEA4EF604 9EDCC1391C208BA0 1 4 1
BD483D69913E3EBFE5FBA87A1FFAB7DCD061055FFB4342C2F27AC01F36833254 EF72D53990BC4805 1 5 1
0B3B2F06C3033B3AFD83BA59B405BCC79BC69801FD3B69931F117B8D754A80EB 9EDCC1391C208BA0 1 3 1", header = TRUE)
x <- read.table(header = TRUE, text = "ClientID EmailMessageId MinDate MaxDate IdSlip WwsCreatedDate ProductArticle ProductGroupName MainProductGroupName CategoryGroupName QtytItems SumAmount iDateDiff
3E34C0C9FC05975CC0F01D7A3DEE73D022538FA04B17A0316178E090C04F84A8 894DB62F7B7A6ED2 31.08.2016 31.08.2016 4A19280A1164CF3F4A701EF9AE97A1F1084B611000B94C02 24.09.2015 item1 item2 item3 item4 1 580.0 -342
3E34C0C9FC05975CC0F01D7A3DEE73D022538FA04B17A0316178E090C04F84A8 894DB62F7B7A6ED2 31.08.2016 31.08.2016 4A19280A1164CF3F4A701EF9AE97A1F1084B611000B94C02 24.09.2015 item1 item2 item3 item4 1 3190.0 -342")
sqldf("
SELECT
ClientId,
EmailMessageId,
null CntTrn,
iDateDiff,
null Score
FROM x
UNION ALL
SELECT
ClientId,
EmailMessageId,
CntTrn,
iDateDiff,
Score
FROM y")

Querying columnar data in SQL Server

I have a table structured as shown below
CustimerId Name Store Bill Item1 Item2 Item3
1 A StoreA 100 Y
2 A StoreB 200 N Y
3 B StoreA 300 N
4 C StoreC 400 Y N Y
Now I want to make one column based on the values in columns Item1, Item2, Item3 which is as below.
CustimerId Name Store Bill BoughtAnySpecialItem
1 A StoreA 100 Y
2 A StoreB 200 Y
3 B StoreA 300 N
4 C StoreC 400 Y
This means if any of the value in columns through Item1 to Item3 is 'Y' I want to make it 'Y' otherwise 'N'. The Item columns are more and or of different name(not like Item-X).
I need the query to do this. Can anyone suggest the best way to do this in SQL server? or at least point me to the right resource. Thanks in advance.
You can use case statement to do that, something like this:
case when Item1 = 'Y' or Item2 = 'Y' or Item3 = 'Y' then 'Y' else 'N' end
Since you have more column's to check you can reverse the IN operator
SELECT *,
CASE WHEN 'Y' in (Item1 , Item2 , Item3) THEN 'Y' ELSE 'N' END as BoughtAnySpecialItem
FROM Yourtable
Now you can easily list the column's in IN opertaor

How to select data from several rows in a single table in one result row?

How to select multiple entries in a single query.
The db table structure represents an excel like spreadsheet. Each observation is a workbook.
Work book 1
1 2
3 4
Work book 2
5 6
7 8
with each db row representing a single cell and observations in separate workbooks.
The table definition is:
observation integer
row_number integer
col_number integer
value integer
The database then looks like this:
observation row_number col_number value
1 1 1 1
1 1 2 2
1 2 1 3
1 2 2 4
2 1 1 5
2 1 2 6
2 2 1 7
2 2 2 8
The question is how to create a single query to:
select observation, value as value1 from database where row_number = 1 and col_number = 2,
select value as value2 from database where row_number = 2 and col_number = 1;
to create:
observation value1 value2
1 2 3
2 6 7
I have tried joins and subqueries.
The basic answer is with a self-join. The table name 'database' is pretty objectionable: I'm going to call it 'spreadsheet'.
SELECT r1.observation, r1.value AS value1, r2.value AS value2
FROM spreadsheet AS r1
JOIN spreadsheet AS r2
ON r1.observation = r2.observation
WHERE r1.row_number = 1
AND r1.col_number = 2
AND r2.row_number = 2
AND r2.col_number = 1
There are plenty of other ways of writing the same query. One of them is:
SELECT r1.observation, r1.value1, r2.value2
FROM (SELECT observation, value AS value1
FROM spreadsheet
WHERE r1.row_number = 1
AND r1.col_number = 2
) AS r1
JOIN (SELECT observation, value AS value2
FROM spreadsheet
WHERE r2.row_number = 2
AND r2.col_number = 1
) AS r2
ON r1.observation = r2.observation
Jonathan has a great answer too but you might find this approach is better if you're going to need to grab more than two values from the observation. I think his joins should be fast but I have no idea how big your tables are.
Mine requires you to specify the (row, column) pairs in multiple places which is a small disadvantage.
select
observation,
min(case when row_number = 1 and column_number = 2 then value end) as value1,
min(case when row_number = 2 and column_number = 1 then value end) as value2
from T
where (row_number = 1 and column_number = 2) or (row_number = 2 and column_number = 1)
group by observation

PLSQL UPDATE BASED ON ROWS FROM OTHER TABLE

I have following tables in APEX A and B.
A has columns:
ID_A;
VALUE;
B has columns:
ID_C_FK;
ID_A_FK
I want to update the VALUE column in table A in rows where ID_A equals ID_A_FK in selected rows from table B where ID_C_FK equal x
For example: A has rows (
ID_A value
------------
1 1
2 1
3 0
4 0
5 0
Table B has rows
ID_C_FK ID_A_FK
------------------
8 4
9 4
9 5
I want to update VALUE in table A only for those rows that have ID_A in rows selected from B and condition to select rows from B is that ID_C_FK equals x = 9; and as a result, table A should end up having rows:
ID_A value
------------
1 1
2 1
3 0
4 1
5 1
How to write such update in PL/SQL?
Thank you for considering my request.
I think this is what you want:
update a
set value = 1
where exists (select 1
from b
where b.id_a_fk = a.id_a and b.id_c_fk = 9
);

How to update the column using two tables based on conditions?

I have two tables such as STR_IndentHeader and STR_IndentDetail.
STR_IndentDetail:
IndentID ItemID ItemStatusID
-------- ------ ------------
1 22 4
1 23 4
2 11 4
2 12 3
2 13 3
STR_IndentHeader:
IndentID StatusID
-------- -----------
1 1
2 1
Here I want to Update the STR_IndentHeader StatusID = 4, When all the STR_IndentDetail.ItemID's ItemStatusID = 4 with respect to IndentID. Else I want to Update the STR_IndentHeader.StatusID = 3.
In the above tables, In STR_IndentDetail, For IndentID "1", all the ItemStatusID of the Items is 4. So we have Update STR_IndentHeader.StatusID = 4.
But for IndentID "2", One Item's(ie. ItemID=11) ItemStatusID = 4 and the Remaining two items ItemStatusID = 3. So In this case, we have to update STR_IndentHeader.StatusID = 3.
I hope it would give better idea. How to do this?
My Desired Result for the above tables would be like this:
STR_IndentHeader:
IndentID StatusID
-------- -----------
1 4
2 3
Based off the information provided I am assuming that you want the statusID in STR_IndentHeader to be the smallest ItemStatusID value from STR_IndentDetail for that IndentID.
If this is the case please try the below:
update STR_IndentHeader
set statusid = minitemstatusid
from
(select indentid,MIN(itemstatusid) as minitemstatusid
from STR_IndentDetail
group by indentid) id
where id.IndentID = STR_IndentHeader.indentid
EDIT:
Based off comments if you want to statically apply an ItemStatusID of 3 if the statusID is not 4 then:
update STR_IndentHeader
set statusid = case minitemstatusid when 4 then 4 else 3 end
from
(select indentid,MIN(itemstatusid) as minitemstatusid
from STR_IndentDetail
group by indentid) id
where id.IndentID = STR_IndentHeader.indentid
Here is one way you can do this using CROSS APPLY available in SQL Server 2005. Hope that helps.
UPDATE SH
SET SH.StatusID = (CASE WHEN DC.DistinctCount = 1 THEN 4 ELSE 3 END)
FROM dbo.STR_IndentHeader SH
CROSS APPLY (
SELECT SD.IndentID
, COUNT(DISTINCT ItemStatusID) AS DistinctCount
FROM dbo.STR_IndentDetail SD
WHERE SH.IndentID = SD.IndentID
GROUP BY SD.IndentID
) DC
This worked for me when I tested it setting up a database with your sample data:
UPDATE STR_IndentHeader ih
SET StatusID = (SELECT MIN(ItemStatusID) FROM STR_IndentDetail id WHERE id.IndentID = ih.IndentID)
WHERE IndentID IN (SELECT DISTINCT IndentID FROM PUR_POIndent WHERE POID = 8)