sql join with multiple conditions on columns - sql

I don't think I can achieve this with unions.
For example, I want all cars where the key-column is "brand" and value-column is "Burago".
On top of that, the key-column price with values between 100 and 220.
Should I do subqueries or something? What if I want to query the key "type" with value "sport" too?
The query only returns something when I use one where clause and returns nothing when use the following query.
select `posts`.`title` from `posts`
inner join `meta` on `posts`.`id` = `meta`.`metable_id`
where `meta`.`key` = "price" and `meta`.`value` between 100 and 220
and `meta`.`key` = "brand" and `meta`.`value` = "Burago"
group by `posts`.`id`
The meta table:
ID | post_id | key | value
----------------------------------------------------
69 | 8 | brand | some-brand
----------------------------------------------------
70 | 8 | type | sport
----------------------------------------------------
70 | 8 | price | 100
----------------------------------------------------
71 | 8 | brand | some-other-brand
----------------------------------------------------
70 | 8 | type | coupe
----------------------------------------------------
72 | 8 | price | 150
----------------------------------------------------
73 | 8 | brand | some-brand
----------------------------------------------------
70 | 8 | type | cabrio
----------------------------------------------------
74 | 8 | price | 100
----------------------------------------------------
75 | 8 | brand | some-brand
----------------------------------------------------
70 | 8 | type | sport
----------------------------------------------------
76 | 8 | price | 250

select `posts`.`title` from `posts`
inner join `meta` on `posts`.`id` = `meta`.`metable_id`
where `meta`.`key` = "price" and `meta`.`value` between 100 and 220
and `meta`.`key` = "brand" and `meta`.`value` = "Burago"
group by `posts`.`id`
having COUNT(DISTINCT `meta`.`key`) = 2

Related

SQL Question Looking Up Value in Same Table

Trying to use a self join in SQL to look up a value in the table and apply it.
Her's what I got:
+-----------------+-----+--------+-----------+
| Acutal Output | | | |
+-----------------+-----+--------+-----------+
| TRKID | Fac | NewFac | BAG_TRKID |
| 449 | 11 | 11 | 999 |
| 473 | 11 | 11 | 737 |
| 477 | 11 | 11 | 737 |
| 482 | 11 | 11 | 737 |
| 737 | 89 | 89 | |
| Desired Out Put | | | |
| TRKID | Fac | NewFac | BAG_TRKID |
| 449 | 11 | 11 | 999 |
| 473 | 11 | 89 | 737 |
| 477 | 11 | 89 | 737 |
| 482 | 11 | 89 | 737 |
| 737 | 89 | 89 | |
+-----------------+-----+--------+-----------+
Here's the code below. I can't seem to get the table that I want. The Bag TrkID's Facility Num is not becoming the TrkID New Facility Num.
Select
TABLEA.TRKID,
TABLEA.FAC,
NVL(TABLEA.FAC, TABLEB.FAC) as NEWFAC,
TABLEA.BAG_TRKID
FROM
(
Select
HSD. TRKID,
HSD.NLPT as FAC,
SBPD.BAG_TRKID
From
HSD
LEFT JOIN
SBPD
ON
SBPD.BAG_TRKID = HSD. TRKID
Where
HSD.SCANDT BETWEEN ‘Yesterday’ and ‘Today’
) TABLEA
LEFT JOIN
(
Select
HSD. TRKID,
HSD.NLPT as FAC,
SBPD.BAG_TRKID
From
HSD
LEFT JOIN
SBPD
ON
SBPD.BAG_TRKID = HSD. TRKID
Where
HSD.SCANDT BETWEEN ‘Yesterday’ and ‘Today’
) TABLEB
ON
TABLEA.TRKID = TABLEB.BAG_TRKID
Perhaps something like
select a.TrkID, a."Facility Number", a.BAG_TRKID, b.TrkID as "NEW Fac"
from tbl a
left join tbl b on (a.TrkID = b.trk_id_reference)
Given the limited information that you've shared, I was able to achieve the expected output with the following query:
SELECT a.TrkID, a.facility_number, a.bag_trkid, b.facility_number as new_facility_number
FROM test_tbl AS a
LEFT JOIN test_tbl AS b ON a.bag_trkid = b.trkid OR (a.bag_trkid IS NULL AND b.trkid = a.trkid);
You want to get the new_facility_number for a row based on its bag_trkid (which can be achieved by this: LEFT JOIN test_tbl AS b ON a.bag_trkid = b.trkid).
BUT the trick is to account for the cases when the Left Table (which I refer as a) does not have a bag_trkid. In this case, we will keep the new_facility_number to be the same as a.facility_number, joining the tables on the trkid solely: OR (a.bag_trkid IS NULL AND b.trkid = a.trkid)

SQL, Update with most recent data info

I have 2 tables shown below:
Table 1
Student ID - DATE_NO - SCORE
Table 2
STUDENT_ID - DATE_NO - HT - WT
Table 1 has the physical test scores and the date of the test for each student while Table 2 lists their height (HT) and weight (WT) and the date they were measured.
Example Data:
Table 1
Student ID | DATE_NO | SCORE |
125 | 3 | 90 |
572 | 6 | 75 |
687 | 11 | 95 |
Table 2
Student_ID | DATE_NO | HT | WT |
125 | 2 | 70 | 150 |
125 | 3 | 72 | 155 |
125 | 6 | 72 | 160 |
572 | 2 | 70 | 200 |
572 | 5 | 70 | 225 |
572 | 8 | 70 | 215 |
572 | 9 | 70 | 220 |
687 | 4 | 65 | 140 |
687 | 7 | 67 | 150 |
687 | 11 | 70 | 155 |
687 | 12 | 67 | 160 |
I am not guaranteed to have the exact same DATE_NO for both HT/WT and the Test score date. I want the most recent HT and WT for each student when they took their physical test. Based on the example data above, the optimal join would give me the table below:
Modified Table 1
Student ID | DATE_NO | HT | WT |
125 | 3 | 72 | 155 |
572 | 6 | 70 | 225 |
687 | 11 | 70 | 155 |
I'd like to use the UPDATE statement on Table 1, so after altering Table 1 with HT int and WT int, I attempt to do the following:
UPDATE T1
SET HT = T2.HT, WT = T2.WT
FROM Table_1 as T1
INNER JOIN Table_2 AS T2 ON T1.STUDENT_ID = T2.STUDENT_ID
WHERE (T1.DATE_NO) >= (T2.DATE_NO)
But the result gives me the FIRST record that meets the criteria. Switching greater than to less than [ >= to <= ] Make the HT/WT for each student the entries for Month 6,8, and 12) when it should be month 3,8, and 11. Any suggestions?
FYI: Won't be able to apply any solutions till Friday.
Is it something like this you're looking for:
UPDATE Q
SET
T1_HT = T2_HT
, T1_WT = T2_WT
FROM
(
SELECT
T1.HT T1_HT
, T1.WT T1_WT
, T2.HT T2_HT
, T2.WT T2_WT
, ROW_NUMBER() OVER (PARTITION BY T1.STUDENT_ID ORDER BY T2.DATE_NO DESC) R
FROM
Table_1 T1
JOIN Table_2 T2 ON
T1.STUDENT_ID = T2.STUDENT_ID
AND T2.DATE_NO <= T1.DATE_NO
) Q
WHERE R = 1
SELECT ts.student_id,
ts.date_no,
hw.ht,
hw.wt
FROM test_scores ts,
ht_wt hw
WHERE hw.student_id = ts.student_id
AND hw.date_no <= ts.date_no
AND hw.date_no =
(SELECT max(date_no)
FROM ht_wt
WHERE date_no <= ts.date_no
AND student_id = ts.student_id)
sql fiddle here

Select / group by multiple columns but count just the values of one column

I have 2 tables.
Table #1: orders
order_id | crit_1 | crit_2 | crit_3 | other
01 | A00 | GER | 49er | x
02 | A00 | GER | 49er | x
03 | A00 | USA | 49er | x
04 | C80 | DEN | 66er | x
05 | B50 | GER | 99er | x
The table orders has 3 important criteria but doesn't have the criterion_4. There is another table with the order_positions which contains multiple criterion_4 entries for each order_id.
Table #2: classifications
crit_1 | crit_2 | crit_3 | crit_4 | class_1 | class_2
A00 | GER | 49er | 4711 | A | 11
A00 | GER | 49er | 4712 | A | 21
A00 | USA | 49er | 4711 | D | 12
A00 | USA | 49er | 4712 | D | 21
B50 | GER | 99er | 4801 | B | 12
B50 | GER | 99er | 4802 | B | 12
B50 | GER | 99er | 4803 | B | 14
C80 | DEN | 66er | 4904 | C | 22
C80 | DEN | 66er | 4905 | C | 21
The table classifications contains classifications for:
orders = class_1 = combination of crit_1, crit_2 & crit_3
order_positions = class_2 = combination of crit_1, crit_2, crit_3
& crit_4
I have a query where I join classifications.class_1 on the table orders to create a list of all orders and their respective classification.
select
orders.order_id,
orders.crit_1,
orders.crit_2,
orders.crit_3,
classifications.class_1
from
orders
left join
classifications
on
orders.crit_1=classifications.crit_1 and
orders.crit_2=classifications.crit_2 and
orders.crit_3=classifications.crit_3
where
orders.others = "..."
group by
orders.order_id,
orders.crit_1,
orders.crit_2,
orders.crit_3,
classifications.class_1
I need a GROUP BY at the end since the table classifications contains multiple entries with the combination of crit_1, crit_2 and crit_3. But this isn't a problem since the needed classification_1 is always the same for each combination of crit_1, crit_2 and crit_3.
Now I want to create another query where I count just the number of each classification_1 for the orders. Something like this:
class_1 | number
A | 12
B | 5
C | 18
. | .
But I don't know how without the whole selection of orders.order_id, orders.crit_1, orders.crit_2, orders.crit_3 and classifications.class_1
I just want to count the class_1 classifications for the query above.
Any suggestions?
edit
I tried it like suggested by Kaushik Nayak:
select
--orders.order_id,
--orders.crit_1,
--orders.crit_2,
--orders.crit_3,
classifications.class_1,
count(*)
from
orders
left join
classifications
on
orders.crit_1=classifications.crit_1 and
orders.crit_2=classifications.crit_2 and
orders.crit_3=classifications.crit_3
where
orders.others = "..."
group by
--orders.order_id,
--orders.crit_1,
--orders.crit_2,
--orders.crit_3,
classifications.class_1
But the results are not correct and I have no idea how to reproduce those numbers.
A few examples:
| class_1 | query w/ | query w/o | query |
| | group by | group by | count(*) |
---------------------------------------------
| A | 654 | 2179 | 1024 |
| B | 371 | 1940 | 667 |
| C | 94 | 238 | 247 |
When I use my query with group by then I get 654 entries for class_1 = A.
When I make my query without group bythen I get 2179 entries for class_1= A.
And when I try the query with Count(*) then I get 1024 entries for class_1 = A.
The last one is definitely not correct.
Just use GROUP BY class_1 for your classifications table and add an EXISTS condition to check if there is an order.
SELECT
c.class_1,
COUNT(c.class_1) "number"
FROM
classifications c
WHERE
EXISTS (
SELECT
1
FROM
orders o
WHERE
o.crit_1 = c.crit_1
AND o.crit_2 = c.crit_2
AND o.crit_3 = c.crit_3
)
GROUP BY
c.class_1
ORDER BY
1;

Multiple self joins plus one inner join

I have two tables: ck_startup and ck_price. The price table contains the columns cu_type, prd_type, part_cd, qty, and dllrs. The startup table is linked to the price table through a one-to-many relationship on ck_startup.prd_type_cd = ck_price.prd_type.
The price table contains multiple entries for the same product/part/qty but under different customer types. Not all customer types have the same unique combination of those three values. I'm trying to create a query that will do two things:
Join some columns from ck_startup onto ck_price (description, and some additional values).
Join ck_price onto itself with a dllrs column for each customer type. So in total I would only have one instance of each unique key of product/part/qty, and a value in each customer's price column if they have one.
I've never worked with self joining tables, and so far I can only get records to show up where both customers have the same options available.
And because someone is going to demand I post sample code, here's the crappy query that doesn't show missing prices:
select pa.*, pac.dllrs from ck_price pa
join ck_price pac on pa.prd_type = pac.prd_type and pa.part_carbon_cd = pac.part_carbon_cd and pa.qty = pac.qty
where pa.cu_type = 'A' and pac.cu_type = 'AC';
EDIT: Here's sample data from the two tables, and how I want them to look when I'm done:
CK_STARTUP
+-----+-----------------+-------------+
| CD | DSC | PRD_TYPE_CD |
+-----+-----------------+-------------+
| 3D | Stuff | SKD3 |
| DC | Different stuff | SKD |
| DN2 | Similar stuff | SKD |
+-----+-----------------+-------------+
CK_PRICE
+---------+-------------+---------+-----+-------+
| CU_TYPE | PRD_TYPE_CD | PART_CD | QTY | DLLRS |
+---------+-------------+---------+-----+-------+
| A | SKD3 | 1 | 100 | 10 |
| A | SKD3 | 1 | 200 | 20 |
| A | SKD3 | 1 | 300 | 30 |
| A | SKD | 1 | 100 | 50 |
| A | SKD | 1 | 200 | 100 |
| AC | SKD3 | 1 | 300 | 30 |
| AC | SKD | 1 | 100 | 100 |
| AC | SKD | 1 | 200 | 200 |
| AC | SKD | 1 | 300 | 300 |
| AC | SKD | 1 | 400 | 400 |
+---------+-------------+---------+-----+-------+
COMBO:
+----+-----------------+---------+-----+---------+----------+
| CD | DSC | PART_CD | QTY | DLLRS_A | DLLRS_AC |
+----+-----------------+---------+-----+---------+----------+
| 3D | Stuff | 1 | 100 | 10 | null |
| 3D | Stuff | 1 | 200 | 20 | null |
| 3D | Stuff | 1 | 300 | 30 | 60 |
| DC | Different stuff | 1 | 100 | 50 | 100 |
| DC | Different stuff | 1 | 200 | 100 | 200 |
| DC | Different stuff | 1 | 300 | null | 300 |
| DC | Different stuff | 1 | 400 | null | 400 |
+----+-----------------+---------+-----+---------+----------+
Ok, take a look at below query and at the results:
SELECT *
FROM (SELECT
cs.cd, cs.dsc, cp.part_cd, cp.qty, cp.dllrs, cp.cu_type
FROM ck_startup cs
JOIN ck_price cp ON (cs.prd_type_cd = cp.prd_type_cd))
PIVOT (SUM(dllrs) AS dlllrs FOR (cu_type) IN ('A' AS a, 'AC' AS ac))
ORDER BY cd, qty
;
Output:
CD DSC PART_CD QTY A_DLLLRS AC_DLLLRS
-------- ----------------- ---------- ------- ---------- ----------
3D Stuff 1 100 10
3D Stuff 1 200 20
3D Stuff 1 300 30 30
DC Different stuff 1 100 50 50
DC Different stuff 1 200 100 100
DC Different stuff 1 300 150
DC Different stuff 1 400 200
DN2 Similar stuff 1 100 50 50
DN2 Similar stuff 1 200 100 100
DN2 Similar stuff 1 300 150
DN2 Similar stuff 1 400 200
It is not what you would expect, because I do not understand why you have different values in DLLRS_AC column that are in the CK_PRICE table? I mean, for example, why do you have 400 in last line of your output, not 200? Why is this value doubled (as others are in DLLRS_AC column)?
If you are using Oracle 10g, you can achieve the same result using DECODE and GROUP BY, take a look:
SELECT
cd,
dsc,
part_cd,
qty,
SUM(DECODE(cu_type, 'A', dllrs, NULL)) AS dllrs_a,
SUM(DECODE(cu_type, 'AC', dllrs, NULL)) AS dllrs_ac
FROM (
SELECT
cs.cd, cs.dsc, cp.part_cd, cp.qty, cp.dllrs, cp.cu_type
FROM ck_startup cs
JOIN ck_price cp ON (cs.prd_type_cd = cp.prd_type_cd)
)
GROUP BY cd, dsc, part_cd, qty
ORDER BY cd, qty;
Result is the same.
If you want to read more about pivoting, I recommend article by Tim Hall: Pivot and Unpivot at Oracle Base

SQL Server 2008 - accumulating column

I would like to accumulate my data as you can see below there is origin table table1:
What is the best query for to do this?
Is possible to do this dynamically - when I add more types of terms??
Table 1
ID | term | value
-----------------------
1 | I | 100
2 | I | 200
3 | II | 100
4 | II | 50
5 | II | 75
6 | III | 50
7 | III | 65
8 | IV | 30
9 | IV | 45
And the result should be like below:
YTD | Acc Value
------------------
I-I | 300
I-II | 525
I-III| 640
I-IV | 715
Thanks
select
(select min(term) from yourtable ) +'-'+term,
(select sum(value) from yourtable t1 where t1.term<=t.term)
from yourtable t
group by term