I'm searching for a sql query that copy entries based on a template into the same table.
the simplified table looks as follows:
product | model | version | attribute | attributeValue
----------|--------|----------|---------------|----------------
A | 1 | 0 | price | 1000
A | 1 | 0 | token | 1
A | 1 | 0 | spc_weight | 130
A | 1 | 0 | spc_volume | 150
A | 1 | 0 | spc_diameter | 12
A | 1 | 0 | colour | blue
A | 1 | 1 | price | 1100
A | 1 | 1 | token | 1
A | 1 | 1 | spc_weight | 130
A | 1 | 1 | spc_volume | 150
A | 1 | 1 | spc_diameter | 12
A | 1 | 1 | colour | blue
B | 1 | 0 | price | 800
B | 1 | 0 | token | 1
B | 1 | 0 | spc_weight | 135
B | 1 | 0 | spc_volume | 150
B | 1 | 0 | spc_diameter | 12
B | 1 | 0 | colour | red
B | 2 | 0 | price | 800
B | 2 | 0 | token | 1
B | 2 | 0 | spc_weight | 140
B | 2 | 0 | spc_volume | 150
B | 2 | 0 | spc_diameter | 12
B | 2 | 0 | colour | red
C | 1 | 0 | price | 800
C | 1 | 0 | token | 2
C | 1 | 0 | spc_weight | 135
C | 1 | 0 | spc_volume | 155
C | 1 | 0 | spc_diameter | 12
C | 1 | 0 | colour | green
i have also created here the table --> http://sqlfiddle.com/#!18/c6b01/3
what's the template? the template product (product+model+version) is user defined.
what data should be copied? all spc_% attributeValue from template product
where should the data be copied? the attributeValue from the template needs to copied into the corresponding attribute from all product that have the same token attribute and are the latest version.
what I have at the moment is
get the template data
select attributeValue from product
where product='B' and model =1 and version =0 and attribute like 'spc_%'
what products are affected
select product, model, max (version) as version from product
where attribute='token' and attributeValue='1'
group by product, model
so the solution in that case would be that all the attribute spc_% for product A model 1 version 1 and product B model 2 version 0 are populated with the attributeValue from the template product b model 1 version 0
thats how the table should look after the update. the values with * are the one that should have been updated based on the template.
product | model | version | attribute | attributeValue
----------|--------|----------|---------------|----------------
A | 1 | 0 | price | 1000
A | 1 | 0 | token | 1
A | 1 | 0 | spc_weight | 130
A | 1 | 0 | spc_volume | 150
A | 1 | 0 | spc_diameter | 12
A | 1 | 0 | colour | blue
A | 1 | 1 | price | 1100
A | 1 | 1 | token | 1
A | 1 | 1 | spc_weight | 135*
A | 1 | 1 | spc_volume | 150*
A | 1 | 1 | spc_diameter | 12*
A | 1 | 1 | colour | blue
B | 1 | 0 | price | 800
B | 1 | 0 | token | 1
B | 1 | 0 | spc_weight | 135
B | 1 | 0 | spc_volume | 150
B | 1 | 0 | spc_diameter | 12
B | 1 | 0 | colour | red
B | 2 | 0 | price | 800
B | 2 | 0 | token | 1
B | 2 | 0 | spc_weight | 135*
B | 2 | 0 | spc_volume | 150*
B | 2 | 0 | spc_diameter | 12*
B | 2 | 0 | colour | red
C | 1 | 0 | price | 800
C | 1 | 0 | token | 2
C | 1 | 0 | spc_weight | 135
C | 1 | 0 | spc_volume | 155
C | 1 | 0 | spc_diameter | 12
C | 1 | 0 | colour | green
thats where I stuck right now. somehow I'm not able to write the inner join and then the update function.
anyone some advice?
it seems that this sql does the job:
with templateCTE as ( select attribute, attributeValue
from product
where product='A'
and attribute like 'spc_%'
and model=1
and version=0),
productsToUpdate as ( select product, model, max (version) as version from product
where attribute='token' and attributeValue='1'
group by product, model ),
selectionToJoin as (select productsToUpdate.product, productsToUpdate.model,productsToUpdate.version, product.attribute, product.attributeValue from productsToUpdate
inner join product on productsToUpdate.product = product.product and productsToUpdate.model= product.model and productsToUpdate.version= product.version)
UPDATE P1
SET P1.[attributeValue] = P2.[attributeValue]
FROM selectionToJoin P1
JOIN templateCTE P2 ON P1.[attribute] = P2.[attribute]
COMMIT;
SELECT * FROM product
regards
You can first select the source rows using a sub query then use join the product table using that resultset. Below update query will work for you -
WITH CTE AS (SELECT [attribute], [attributeValue]
FROM product
WHERE [attribute] LIKE 'spc_%'
AND [product] = 'B'
AND [model] = 1
AND [version] = 0)
UPDATE P1
SET P1.[attributeValue] = P2.[attributeValue]
FROM product P1
JOIN CTE P2 ON P1.[attribute] = P2.[attribute]
Here is the fiddle.
Related
While going through SQL columns, if we find text match "NEW" in Calc column, update the incrementing a count starting with 1 in Results column.
It should look like this on the output:
The following uses an id column to resolve the order issue. Replace that with your corresponding expression. This also addresses the requirement to start the display sequence with 1 and also show 0 for the 'NEW' rows.
The SQL (updated):
SELECT logs.*
, CASE WHEN text = 'NEW' THEN 0
ELSE
COALESCE(SUM(CASE WHEN text = 'NEW' THEN 1 END) OVER (PARTITION BY xrank ORDER BY id)+1, 1)
END AS display
FROM logs
ORDER BY id
The result:
+----+-------+------+---------+
| id | xrank | text | display |
+----+-------+------+---------+
| 1 | 1 | A | 1 |
| 2 | 1 | B | 1 |
| 3 | 1 | C | 1 |
| 4 | 1 | NEW | 0 |
| 5 | 1 | D | 2 |
| 6 | 1 | Q | 2 |
| 7 | 1 | B | 2 |
| 8 | 1 | NEW | 0 |
| 9 | 1 | D | 3 |
| 10 | 1 | Z | 3 |
| 11 | 2 | A | 1 |
| 12 | 2 | B | 1 |
| 13 | 2 | C | 1 |
| 14 | 2 | NEW | 0 |
| 15 | 2 | D | 2 |
| 16 | 2 | Q | 2 |
| 17 | 2 | B | 2 |
| 18 | 2 | NEW | 0 |
| 19 | 2 | D | 3 |
| 20 | 2 | Z | 3 |
+----+-------+------+---------+
You need a column that specifies the ordering for the table. With that, just use a cumulative sum:
select t.*,
1 + sum(case when Calc = 'NEW' then 1 else 0 end) over (partition by Rank_Id order by Seq) as display
from t;
I need to create a new column that restarts at every 0 value of Column Repeated Call of each Customer_ID:
+-------------+---------+----------------------+---------------+
| Customer_ID | Call_ID | Days Since Last Call | Repeated Call |
+-------------+---------+----------------------+---------------+
| 1 | 1 | Null | 0 |
| 1 | 2 | 45 | 0 |
| 1 | 3 | 0 | 1 |
| 1 | 4 | 0 | 1 |
| 1 | 5 | 0 | 1 |
| 1 | 6 | 48 | 0 |
| 1 | 7 | 1 | 1 |
| 2 | 8 | Null | 0 |
| 2 | 9 | 1 | 1 |
+-------------+---------+----------------------+---------------+
In to something like this:
+-------------+---------+----------------------+---------------+-------------+
| Customer_ID | Call_ID | Days Since Last Call | Repeated Call | Order_Group |
+-------------+---------+----------------------+---------------+-------------+
| 1 | 1 | Null | 0 | 1 |
| 1 | 2 | 45 | 0 | 2 |
| 1 | 3 | 0 | 1 | 2 |
| 1 | 4 | 0 | 1 | 2 |
| 1 | 5 | 0 | 1 | 2 |
| 1 | 6 | 48 | 0 | 3 |
| 1 | 7 | 1 | 1 | 3 |
| 2 | 8 | Null | 0 | 1 |
| 2 | 9 | 1 | 1 | 1 |
+-------------+---------+----------------------+---------------+-------------+
Appreciate your suggestion, thanks!
You can use SUM() window function:
select t.*,
sum(case when Repeated_Call = 0 then 1 else 0 end)
over (partition by Customer_ID order by Call_Id) Order_Group
from tablename t
See the demo (for MySql but it is standard SQL).
Results:
| Customer_ID | Call_ID | Days Since Last Call | Repeated_Call | Order_Group |
| ----------- | ------- | -------------------- | ------------- | ----------- |
| 1 | 1 | | 0 | 1 |
| 1 | 2 | 45 | 0 | 2 |
| 1 | 3 | 0 | 1 | 2 |
| 1 | 4 | 0 | 1 | 2 |
| 1 | 5 | 0 | 1 | 2 |
| 1 | 6 | 48 | 0 | 3 |
| 1 | 7 | 1 | 1 | 3 |
| 2 | 8 | | 0 | 1 |
| 2 | 9 | 1 | 1 | 1 |
You can calculation every 0 value in column Repeated Call (for each customer) using window analytic function COUNT with ROWS UNBOUNDED PRECEDING:
SELECT *,
COUNT(CASE WHEN Repeated Call=0 THEN 1 ELSE NULL END )OVER(PARTITION BY Customer_ID
ORDER BY Call_ID ROWS UNBOUNDED PRECEDING)Order_Gr FROM Table
I am trying to join three separate tables based on certain criteria. Here are table examples:
TABLE A
+----+------------+----------+---------+
| id | entry num | line num | inv line|
+----+------------+----------+---------+
| 1 | 1 | 1 | 1 |
| 2 | 1 | 1 | 2 |
| 3 | 2 | 1 | 1 |
| 4 | 2 | 2 | 1 |
| 5 | 3 | 1 | 1 |
| 6 | 3 | 1 | 2 |
| 7 | 3 | 1 | 3 |
+----+------------+--------+-----------+
TABLE B
+----+------------+----------+---------+
| id | entry num | line num | code |
+----+------------+----------+---------+
| 1 | 1 | 1 | 100 |
| 2 | 2 | 1 | 370 |
| 3 | 2 | 2 | 120 |
| 4 | 3 | 1 | 300 |
+----+------------+--------+-----------+
TABLE C
+----+------------+--------+-----------+
| id | rate | amt | code |
+----+------------+--------+-----------+
| 1 | 25% | $50 | 100 |
| 2 | 50% | $20 | 370 |
| 3 | 50% | $25 | 120 |
| 4 | 30% | $150 | 300 |
+----+------------+----------+---------+
I need the final table to look like this, but I am at a loss on how to write the syntax:
FINAL TABLE
+----+------------+----------+---------+---------+---------+---------+
| id | entry num | line num | inv line| code | rate | amt |
+----+------------+----------+---------+---------+---------+---------+
| 1 | 1 | 1 | 1 | 100 | 25% | $50 |
| 2 | 1 | 1 | 2 | 100 | 25% | $50 |
| 3 | 2 | 1 | 1 | 370 | 50% | $20 |
| 4 | 2 | 2 | 1 | 120 | 50% | $25 |
| 5 | 3 | 1 | 1 | 300 | 30% | $150 |
| 6 | 3 | 1 | 2 | 300 | 30% | $150 |
| 7 | 3 | 1 | 3 | 300 | 30% | $150 |
+----+------------+----------+---------+---------+---------+---------+
Ultimately, I need table A and B joined where both entry num and line num match, but then I need to show each individual row for the inv line number.
For example, entry num 3 / line num 1 will has 3 invoice numbers. All entry num 3/ line num 1 will have the code 300, 30% rate, and $150 amount, but I need to visibly see that there are 3 invoice lines.
I've tried to join tables, group them, and get total counts, but to no avail. Thanks for your help!
I think that you need to create joins between TableA and Table B on EntryNum and LineNum, and then between TableB and TableC on Code. Your SQL should look like:
SELECT A.ID, A.EntryNum, A.LineNum, A.InvLine, B.Code, C.Rate, C.Amt
FROM TableC AS C INNER JOIN (TableB AS B INNER JOIN TableA AS A ON (B.LineNum = A.LineNum) AND (B.EntryNum = A.EntryNum))
ON C.Code = B.Code;
Which produces the result that you want:
Regards,
I have the following T-SQL code:
select
id,
(case
when n in(Bla1', 'Bla2') then 1
when n = 'Bla3' then 99
else 0
end) as c
from
hello
Running this code outputs this result:
| id | c |
+--------+----+
| 577140 | 0 |
| 577140 | 1 |
| 577140 | 0 |
| 577140 | 0 |
| 577140 | 99 |
| 577141 | 0 |
| 577141 | 0 |
| 577141 | 0 |
| 577142 | 0 |
| 577142 | 0 |
| 577142 | 1 |
How can I modify the code to get the following output?
| id | c |
+--------+----+
| 577140 | 99 |
| 577141 | 0 |
| 577142 | 1 |
Rule
For each id: If 99 exists, then c becomes 99. If not, either 1 or 0, depending if any 1 exists.
You can use aggregation:
select id,
max(case when n in ('Bla1', 'Bla2') then 1
when n = 'Bla3' then 99
else 0
end) as c
from hello
group by id;
My table returns results as following (skips row if HourOfDay does not have data for particular ID)
ID HourOfDay Counts
--------------------------
1 5 5
1 13 10
1 23 3
..........................HourOfDay up till 23
2 9 1
and so on.
What I am trying to achieve is to force showing rows displaying 0 for HoursOfDay, which don't have data, like following:
ID HourOfDay Counts
--------------------------
1 0 0
1 1 0
1 2 0
1......................
1 5 5
1 6 0
1......................
1 23 3
2 0 0
2 1 0
etc.
I have researched around about it. It looks like I can achieve this result if I create an extra table and outer join it. So I have created table variable in SP (as a temp workaround)
DECLARE #Hours TABLE
(
[Hour] INT NULL
);
INSERT INTO #Hours VALUES (0),(1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12)
,(13),(14),(15),(16),(17),(18),(19),(20),(21),(22),(23);
However, no matter how I join it, it does not achieve desired result.
How do I proceed? Do I add extra columns to join on? Completely different approach? Any hint in the right direction is appreciated!
Using a derived table for the distinct Ids cross joined to #Hours, left joined to your table:
select
i.Id
, h.Hour
, coalesce(t.Counts,0) as Counts
from (select distinct Id from t) as i
cross join #Hours as h
left join t
on i.Id = t.Id
and h.Hour = t.HourOfDay
rextester demo: http://rextester.com/XFZYX88502
returns:
+----+------+--------+
| Id | Hour | Counts |
+----+------+--------+
| 1 | 0 | 0 |
| 1 | 1 | 0 |
| 1 | 2 | 0 |
| 1 | 3 | 0 |
| 1 | 4 | 0 |
| 1 | 5 | 5 |
| 1 | 6 | 0 |
| 1 | 7 | 0 |
| 1 | 8 | 0 |
| 1 | 9 | 0 |
| 1 | 10 | 0 |
| 1 | 11 | 0 |
| 1 | 12 | 0 |
| 1 | 13 | 10 |
| 1 | 14 | 0 |
| 1 | 15 | 0 |
| 1 | 16 | 0 |
| 1 | 17 | 0 |
| 1 | 18 | 0 |
| 1 | 19 | 0 |
| 1 | 20 | 0 |
| 1 | 21 | 0 |
| 1 | 22 | 0 |
| 1 | 23 | 3 |
| 2 | 0 | 0 |
| 2 | 1 | 0 |
| 2 | 2 | 0 |
| 2 | 3 | 0 |
| 2 | 4 | 0 |
| 2 | 5 | 0 |
| 2 | 6 | 0 |
| 2 | 7 | 0 |
| 2 | 8 | 0 |
| 2 | 9 | 1 |
| 2 | 10 | 0 |
| 2 | 11 | 0 |
| 2 | 12 | 0 |
| 2 | 13 | 0 |
| 2 | 14 | 0 |
| 2 | 15 | 0 |
| 2 | 16 | 0 |
| 2 | 17 | 0 |
| 2 | 18 | 0 |
| 2 | 19 | 0 |
| 2 | 20 | 0 |
| 2 | 21 | 0 |
| 2 | 22 | 0 |
| 2 | 23 | 0 |
+----+------+--------+